Merge commit 'ce97caf83654441074df1d25070f94ef3251971a' into dev-release
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java index 3cd04b1..c443620 100644 --- a/src/main/java/com/android/tools/r8/D8.java +++ b/src/main/java/com/android/tools/r8/D8.java
@@ -11,7 +11,6 @@ import com.android.tools.r8.dex.Marker; import com.android.tools.r8.dex.Marker.Tool; import com.android.tools.r8.graph.AppInfo; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.DexProgramClass; @@ -33,7 +32,6 @@ import com.android.tools.r8.utils.CfgPrinter; import com.android.tools.r8.utils.ExceptionUtils; import com.android.tools.r8.utils.InternalOptions; -import com.android.tools.r8.utils.InternalOptions.DesugarState; import com.android.tools.r8.utils.StringDiagnostic; import com.android.tools.r8.utils.ThreadUtils; import com.android.tools.r8.utils.Timing; @@ -167,10 +165,7 @@ DexApplication app = new ApplicationReader(inputApp, options, timing).read(executor); PrefixRewritingMapper rewritePrefix = options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options); - AppInfo appInfo = - options.desugarState == DesugarState.ON - ? new AppInfoWithClassHierarchy(app) - : new AppInfo(app); + AppInfo appInfo = new AppInfo(app); final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java index 5c815bc..5781482 100644 --- a/src/main/java/com/android/tools/r8/D8Command.java +++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -405,8 +405,6 @@ assert !internal.enableLambdaMerging; assert !internal.enableTreeShakingOfLibraryMethodOverrides; - // TODO(b/137168535) Disable non-null tracking for now. - internal.enableNonNullTracking = false; internal.desugarState = getDesugarState(); internal.encodeChecksums = getIncludeClassesChecksum(); internal.dexClassChecksumFilter = getDexClassChecksumFilter();
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java index bda3597..0b1fead 100644 --- a/src/main/java/com/android/tools/r8/ExtractMarker.java +++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -26,7 +26,6 @@ import java.util.Collection; import java.util.concurrent.ExecutionException; -@Keep public class ExtractMarker { public static class VdexOrigin extends Origin {
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java index dea3bb8..4ba88f4 100644 --- a/src/main/java/com/android/tools/r8/L8.java +++ b/src/main/java/com/android/tools/r8/L8.java
@@ -9,7 +9,6 @@ import com.android.tools.r8.dex.ApplicationReader; import com.android.tools.r8.dex.Marker.Tool; import com.android.tools.r8.graph.AppInfo; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.GraphLense; @@ -122,7 +121,7 @@ options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options); app = new L8TreePruner(options).prune(app, rewritePrefix); - AppInfo appInfo = new AppInfoWithClassHierarchy(app); + AppInfo appInfo = new AppInfo(app); AppView<?> appView = AppView.createForL8(appInfo, options, rewritePrefix); IRConverter converter = new IRConverter(appView, timing);
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java index ff26467..b1072df 100644 --- a/src/main/java/com/android/tools/r8/L8Command.java +++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -174,8 +174,6 @@ assert !internal.enableLambdaMerging; assert !internal.enableTreeShakingOfLibraryMethodOverrides; - // TODO(b/137168535) Disable non-null tracking for now. - internal.enableNonNullTracking = false; assert internal.desugarState == DesugarState.ON; assert internal.enableInheritanceClassInDexDistributor; internal.enableInheritanceClassInDexDistributor = false;
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java index 9a26221..5fe37ab 100644 --- a/src/main/java/com/android/tools/r8/PrintUses.java +++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -100,7 +100,7 @@ @Override public boolean registerInvokeVirtual(DexMethod method) { - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method); DexEncodedMethod target = resolutionResult.isVirtualTarget() ? resolutionResult.getSingleTarget() : null; if (target != null && target.method != method) { @@ -203,9 +203,7 @@ private void addField(DexField field, boolean isStatic) { addType(field.type); DexEncodedField baseField = - isStatic - ? appInfo.lookupStaticTarget(field.holder, field) - : appInfo.lookupInstanceTarget(field.holder, field); + isStatic ? appInfo.lookupStaticTarget(field) : appInfo.lookupInstanceTarget(field); if (baseField != null && baseField.holder() != field.holder) { field = baseField.field; } @@ -250,7 +248,7 @@ private void registerMethod(ProgramMethod method) { DexEncodedMethod superTarget = appInfo - .resolveMethod(method.getHolder(), method.getReference()) + .resolveMethodOn(method.getHolder(), method.getReference()) .lookupInvokeSpecialTarget(context, appInfo); if (superTarget != null) { addMethod(superTarget.method); @@ -275,7 +273,8 @@ // If clazz overrides any methods in superType, we should keep those as well. clazz.forEachMethod( method -> { - ResolutionResult resolutionResult = appInfo.resolveMethod(superType, method.method); + ResolutionResult resolutionResult = + appInfo.resolveMethodOn(superType, method.method, superType != clazz.superType); DexEncodedMethod dexEncodedMethod = resolutionResult.getSingleTarget(); if (dexEncodedMethod != null) { addMethod(dexEncodedMethod.method);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index 51b0aaf..382dd08 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -50,7 +50,6 @@ import com.android.tools.r8.ir.optimize.enums.EnumValueInfoMapCollector; import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; import com.android.tools.r8.jar.CfApplicationWriter; -import com.android.tools.r8.kotlin.KotlinInfoCollector; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.Minifier; import com.android.tools.r8.naming.NamingLens; @@ -318,11 +317,6 @@ } } - // Compute kotlin info before setting the roots and before - // kotlin metadata annotation is removed. - KotlinInfoCollector.computeKotlinInfoForProgramClasses( - application, appView, executorService); - // Add synthesized -assumenosideeffects from min api if relevant. if (options.isGeneratingDex()) { if (!ProguardConfigurationUtils.hasExplicitAssumeValuesOrAssumeNoSideEffectsRuleForMinSdk(
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java index e9997b0..6f4e958 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -167,8 +167,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forBinop(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java index 85c4773..1290256 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -43,8 +43,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forArrayLength(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java index 010bcfd..02e20ea 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.MemberType; import com.android.tools.r8.ir.code.ValueType; @@ -88,8 +88,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forArrayGet(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java index 52df928..1976942 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.MemberType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -78,8 +78,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forArrayPut(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java index 19ca32e..a46e68c 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -40,7 +42,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerCheckCast(type); } @@ -59,8 +61,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forCheckCast(type, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forCheckCast(type, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java index 259bfe3..8d128be 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.Cmp; import com.android.tools.r8.ir.code.Cmp.Bias; @@ -92,8 +92,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forBinop(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java index a203742..05d8568 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -5,6 +5,8 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -71,7 +73,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerConstClass(type); } @@ -82,8 +84,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forConstClass(type, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forConstClass(type, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java index 04e569b..89fae02 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -4,8 +4,9 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexMethodHandle; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.graph.UseRegistry.MethodHandleUse; @@ -40,7 +41,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerMethodHandle(handle, MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY); } @@ -58,8 +59,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forConstMethodHandle(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java index a67c3ed..8283278 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -4,8 +4,9 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; -import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -40,7 +41,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerProto(type); } @@ -58,8 +59,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forConstMethodType(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java index c3be968..889a63c 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -35,8 +35,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forConstInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java index da5d12a..5451986 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -133,8 +133,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forConstInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java index 08ee865..3b113cb 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; -import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -65,8 +65,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forConstInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java index fbc4939..94eadd1 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -5,8 +5,9 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; -import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -64,7 +65,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { if (nameComputationInfo.needsToRegisterReference()) { assert item.isDexType(); registry.registerTypeReference(item.asDexType()); @@ -81,8 +82,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forDexItemBasedConstString(item, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forDexItemBasedConstString(item, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java index 5812288..7e31f5b 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -5,7 +5,9 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -64,7 +66,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { switch (opcode) { case Opcodes.GETFIELD: registry.registerInstanceFieldRead(field); @@ -123,17 +125,16 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { switch (opcode) { case Opcodes.GETSTATIC: - return inliningConstraints.forStaticGet(field, invocationContext); + return inliningConstraints.forStaticGet(field, context); case Opcodes.PUTSTATIC: - return inliningConstraints.forStaticPut(field, invocationContext); + return inliningConstraints.forStaticPut(field, context); case Opcodes.GETFIELD: - return inliningConstraints.forInstanceGet(field, invocationContext); + return inliningConstraints.forInstanceGet(field, context); case Opcodes.PUTFIELD: - return inliningConstraints.forInstancePut(field, invocationContext); + return inliningConstraints.forInstancePut(field, context); default: throw new Unreachable("Unexpected opcode " + opcode); }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java index 88d5ece..72f5be9 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -8,6 +8,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -293,8 +294,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java index 412c97c7..bbb8996 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -60,8 +60,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forJumpInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java index ebc6a98..a6d0fca 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.If.Type; @@ -93,8 +93,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forJumpInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java index c2f34f7..24c81a5 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.If.Type; @@ -94,8 +94,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forJumpInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java index 986d11f..4ce64a4 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -51,8 +51,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java index a355f58..115d27a 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -4,7 +4,9 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -49,7 +51,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType context) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerInitClass(clazz); } @@ -66,7 +68,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType context) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forInitClass(clazz, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java index 5d0997f..ca6b7ed 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -49,7 +51,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerTypeReference(type); } @@ -67,8 +69,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forInstanceOf(type, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forInstanceOf(type, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java index d3cc826..05f1181 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -4,8 +4,11 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ClasspathMethod; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -28,7 +31,15 @@ return printer.toString(); } - public void registerUse(UseRegistry registry, DexType clazz) { + public void registerUse(UseRegistry registry, ProgramMethod context) { + internalRegisterUse(registry, context); + } + + public void registerUseForDesugaring(UseRegistry registry, ClasspathMethod context) { + internalRegisterUse(registry, context); + } + + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { // Intentionally empty. } @@ -153,6 +164,5 @@ } public abstract ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context); }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java index 1a5dd5c..1146ff2 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; @@ -83,7 +84,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { switch (opcode) { case Opcodes.INVOKEINTERFACE: registry.registerInvokeInterface(method); @@ -94,7 +95,7 @@ case Opcodes.INVOKESPECIAL: if (method.name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME)) { registry.registerInvokeDirect(method); - } else if (method.holder == clazz) { + } else if (method.holder == context.getHolderType()) { registry.registerInvokeDirect(method); } else { registry.registerInvokeSuper(method); @@ -196,8 +197,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { GraphLense graphLense = inliningConstraints.getGraphLense(); AppView<?> appView = inliningConstraints.getAppView(); DexMethod target = method; @@ -215,7 +215,7 @@ if (appView.dexItemFactory().isConstructor(target)) { type = Type.DIRECT; assert noNeedToUseGraphLense(target, type, graphLense); - } else if (target.holder == invocationContext) { + } else if (target.holder == context.type) { // The method could have been publicized. type = graphLense.lookupMethod(target, null, Type.DIRECT).getType(); assert type == Type.DIRECT || type == Type.VIRTUAL; @@ -232,37 +232,39 @@ } break; - case Opcodes.INVOKESTATIC: { - // Static invokes may have changed as a result of horizontal class merging. - GraphLenseLookupResult lookup = graphLense.lookupMethod(target, null, Type.STATIC); - target = lookup.getMethod(); - type = lookup.getType(); - break; - } - - case Opcodes.INVOKEVIRTUAL: { - type = Type.VIRTUAL; - // Instructions that target a private method in the same class translates to - // invoke-direct. - if (target.holder == invocationContext) { - DexClass clazz = appView.definitionFor(target.holder); - if (clazz != null && clazz.lookupDirectMethod(target) != null) { - type = Type.DIRECT; - } + case Opcodes.INVOKESTATIC: + { + // Static invokes may have changed as a result of horizontal class merging. + GraphLenseLookupResult lookup = graphLense.lookupMethod(target, null, Type.STATIC); + target = lookup.getMethod(); + type = lookup.getType(); } - - // Virtual invokes may have changed to interface invokes as a result of member rebinding. - GraphLenseLookupResult lookup = graphLense.lookupMethod(target, null, type); - target = lookup.getMethod(); - type = lookup.getType(); break; - } + + case Opcodes.INVOKEVIRTUAL: + { + type = Type.VIRTUAL; + // Instructions that target a private method in the same class translates to + // invoke-direct. + if (target.holder == context.type) { + DexClass clazz = appView.definitionFor(target.holder); + if (clazz != null && clazz.lookupDirectMethod(target) != null) { + type = Type.DIRECT; + } + } + + // Virtual invokes may have changed to interface invokes as a result of member rebinding. + GraphLenseLookupResult lookup = graphLense.lookupMethod(target, null, type); + target = lookup.getMethod(); + type = lookup.getType(); + } + break; default: throw new Unreachable("Unexpected opcode " + opcode); } - return inliningConstraints.forInvoke(target, type, invocationContext); + return inliningConstraints.forInvoke(target, type, context); } private static boolean noNeedToUseGraphLense(
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java index 458bc23..fac04cd 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -6,7 +6,9 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexCallSite; +import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexMethodHandle; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.DexValue; @@ -82,7 +84,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerCallSite(callSite); } @@ -110,8 +112,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forInvokeCustom(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java index 7e678dc..2fc78ea 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.CompilationError; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -45,7 +45,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { throw error(); }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java index 3901a1a..6cc49de 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -58,8 +58,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java index 80d6a8e..0680d73 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -87,8 +87,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forLoad(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java index c2775a0..f34a7d7 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -139,8 +139,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forBinop(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java index 6386b3c..7fd0167 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.Monitor.Type; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -52,8 +52,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forMonitor(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java index d12d76b..1f787f8 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -45,7 +47,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerTypeReference(type); } @@ -64,8 +66,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forInvokeMultiNewArray(type, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forInvokeMultiNewArray(type, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java index 02b2a83..cd61c29 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -81,8 +81,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forUnop(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java index be087af..8bd1249 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -39,7 +41,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { registry.registerNewInstance(type); } @@ -55,8 +57,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forNewInstance(type, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forNewInstance(type, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java index 1ce6048..9ef5f1b 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -5,6 +5,8 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; @@ -78,7 +80,7 @@ } @Override - public void registerUse(UseRegistry registry, DexType clazz) { + void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { if (!type.isPrimitiveArrayType()) { registry.registerTypeReference(type); } @@ -98,8 +100,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { - return inliningConstraints.forNewArrayEmpty(type, invocationContext); + InliningConstraints inliningConstraints, DexProgramClass context) { + return inliningConstraints.forNewArrayEmpty(type, context); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java index be9170c..4578bff 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -39,8 +39,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java index dbedc8a..afbff92 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -152,8 +152,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forUnop(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java index 2dac0c6..93febbb 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.Position; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -67,8 +67,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java index e1b6de1..5934617 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -75,8 +75,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forReturn(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java index 0bbe1cd..c9d7f51 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -44,8 +44,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forReturn(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java index 5821c3f..ef291d0 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -6,7 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -315,8 +315,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java index d560b82..d8f13d1 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -86,8 +86,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forStore(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java index bfbe30f..3169da0 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -103,8 +103,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forJumpInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java index c0c094d..9b88cb5 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -46,8 +46,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, - DexType invocationContext) { + InliningConstraints inliningConstraints, DexProgramClass context) { return inliningConstraints.forJumpInstruction(); } }
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java index ef53aaa..0b5d100 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfo.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -3,28 +3,17 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.graph; -import com.android.tools.r8.graph.ResolutionResult.ArrayCloneMethodResult; -import com.android.tools.r8.graph.ResolutionResult.ClassNotFoundResult; -import com.android.tools.r8.graph.ResolutionResult.IllegalAccessOrNoSuchMethodResult; -import com.android.tools.r8.graph.ResolutionResult.IncompatibleClassResult; -import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult; -import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult; +import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult; import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter; -import com.android.tools.r8.ir.desugar.LambdaDescriptor; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.BooleanBox; import com.android.tools.r8.utils.InternalOptions; -import com.android.tools.r8.utils.ListUtils; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; public class AppInfo implements DexDefinitionSupplier { @@ -33,29 +22,44 @@ private final DexItemFactory dexItemFactory; // TODO(b/151804585): Remove this cache. - private final ConcurrentHashMap<DexType, Map<DexField, DexEncodedField>> fieldDefinitionsCache = - new ConcurrentHashMap<>(); + private final ConcurrentHashMap<DexType, Map<DexField, DexEncodedField>> fieldDefinitionsCache; // For some optimizations, e.g. optimizing synthetic classes, we may need to resolve the current // class being optimized. - private final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses = - new ConcurrentHashMap<>(); + private final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses; // Set when a new AppInfo replaces a previous one. All public methods should verify that the // current instance is not obsolete, to ensure that we almost use the most recent AppInfo. - private boolean obsolete; + private final BooleanBox obsolete; public AppInfo(DexApplication application) { - this.app = application; - this.dexItemFactory = app.dexItemFactory; + this(application, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), new BooleanBox()); } - protected AppInfo(AppInfo previous) { - assert !previous.isObsolete(); - this.app = previous.app; - this.dexItemFactory = app.dexItemFactory; - this.fieldDefinitionsCache.putAll(previous.fieldDefinitionsCache); - copyMetadataFromPrevious(previous); + // For desugaring. + protected AppInfo(AppInfo appInfo) { + this(appInfo.app, appInfo.fieldDefinitionsCache, appInfo.synthesizedClasses, appInfo.obsolete); + } + + // For AppInfoWithLiveness. + protected AppInfo(AppInfoWithClassHierarchy previous) { + this( + ((AppInfo) previous).app, + new ConcurrentHashMap<>(((AppInfo) previous).fieldDefinitionsCache), + new ConcurrentHashMap<>(((AppInfo) previous).synthesizedClasses), + new BooleanBox()); + } + + private AppInfo( + DexApplication application, + ConcurrentHashMap<DexType, Map<DexField, DexEncodedField>> fieldDefinitionsCache, + ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses, + BooleanBox obsolete) { + this.app = application; + this.dexItemFactory = application.dexItemFactory; + this.fieldDefinitionsCache = fieldDefinitionsCache; + this.synthesizedClasses = synthesizedClasses; + this.obsolete = obsolete; } protected InternalOptions options() { @@ -67,15 +71,15 @@ } public boolean isObsolete() { - return obsolete; + return obsolete.get(); } public void markObsolete() { - obsolete = true; + obsolete.set(); } public void unsetObsolete() { - obsolete = false; + obsolete.unset(); } public boolean checkIfObsolete() { @@ -205,31 +209,19 @@ fieldDefinitionsCache.remove(type); } - // TODO(b/147578480): Temporary API since most of the code base use a type instead - // of a DexProgramClass as the invocationContext. - DexProgramClass toProgramClass(DexType type) { - assert type.isClassType(); - return DexProgramClass.asProgramClassOrNull(definitionFor(type)); - } - /** * Lookup static method on the method holder, or answers null. * * @param method the method to lookup - * @param invocationContext the class the invoke is contained in, i.e., the holder of the caller. + * @param context the method the invoke is contained in, i.e., the caller. * @return The actual target for {@code method} if on the holder, or {@code null}. */ - @Deprecated // TODO(b/147578480): Remove - public DexEncodedMethod lookupStaticTargetOnItself(DexMethod method, DexType invocationContext) { - return lookupStaticTargetOnItself(method, toProgramClass(invocationContext)); - } - public final DexEncodedMethod lookupStaticTargetOnItself( - DexMethod method, DexProgramClass invocationContext) { - if (method.holder != invocationContext.type) { + DexMethod method, ProgramMethod context) { + if (method.holder != context.getHolderType()) { return null; } - DexEncodedMethod singleTarget = invocationContext.lookupDirectMethod(method); + DexEncodedMethod singleTarget = context.getHolder().lookupDirectMethod(method); if (singleTarget != null && singleTarget.isStatic()) { return singleTarget; } @@ -240,334 +232,21 @@ * Lookup direct method on the method holder, or answers null. * * @param method the method to lookup - * @param invocationContext the class the invoke is contained in, i.e., the holder of the caller. + * @param context the method the invoke is contained in, i.e., the caller. * @return The actual target for {@code method} if on the holder, or {@code null}. */ - @Deprecated // TODO(b/147578480): Remove - public DexEncodedMethod lookupDirectTargetOnItself(DexMethod method, DexType invocationContext) { - return lookupDirectTargetOnItself(method, toProgramClass(invocationContext)); - } - public final DexEncodedMethod lookupDirectTargetOnItself( - DexMethod method, DexProgramClass invocationContext) { - if (method.holder != invocationContext.type) { + DexMethod method, ProgramMethod context) { + if (method.holder != context.getHolderType()) { return null; } - DexEncodedMethod singleTarget = invocationContext.lookupDirectMethod(method); + DexEncodedMethod singleTarget = context.getHolder().lookupDirectMethod(method); if (singleTarget != null && !singleTarget.isStatic()) { return singleTarget; } return null; } - /** - * Implements resolution of a method descriptor against a target type. - * - * <p>This method will query the definition of the holder to decide on which resolution to use. If - * the holder is an interface, it delegates to {@link #resolveMethodOnInterface(DexType, - * DexMethod)}, otherwise {@link #resolveMethodOnClass(DexType, DexMethod)} is used. - * - * <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the - * kind of a method reference. - */ - public ResolutionResult resolveMethod(DexType holder, DexMethod method) { - assert checkIfObsolete(); - if (holder.isArrayType()) { - return resolveMethodOnArray(holder, method); - } - DexClass definition = definitionFor(holder); - if (definition == null) { - return ClassNotFoundResult.INSTANCE; - } - return resolveMethod(definition, method); - } - - public ResolutionResult resolveMethod(DexClass holder, DexMethod method) { - return holder.isInterface() - ? resolveMethodOnInterface(holder, method) - : resolveMethodOnClass(holder, method); - } - - /** - * Implements resolution of a method descriptor against a target type. - * - * <p>The boolean isInterface parameter denotes if the method reference is an interface method - * reference, and if so method resolution is done according to interface method resolution. - * - * @param holder Type at which to initiate the resolution. - * @param method Method descriptor for resolution (the field method.holder is ignored). - * @param isInterface Indicates if resolution is to be done according to class or interface. - * @return The result of resolution. - */ - public ResolutionResult resolveMethod(DexType holder, DexMethod method, boolean isInterface) { - assert checkIfObsolete(); - return isInterface - ? resolveMethodOnInterface(holder, method) - : resolveMethodOnClass(holder, method); - } - - /** - * Implements resolution of a method descriptor against an array type. - * - * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">Section - * 10.7 of the Java Language Specification</a>. All invokations will have target java.lang.Object - * except clone which has no target. - */ - private ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) { - assert checkIfObsolete(); - assert holder.isArrayType(); - if (method.name == dexItemFactory.cloneMethodName) { - return ArrayCloneMethodResult.INSTANCE; - } else { - return resolveMethodOnClass(dexItemFactory.objectType, method); - } - } - - /** - * Implements resolution of a method descriptor against a class type. - * <p> - * See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3"> - * Section 5.4.3.3 of the JVM Spec</a>. - * <p> - * The resolved method is not the method that will actually be invoked. Which methods gets - * invoked depends on the invoke instruction used. However, it is always safe to rewrite - * any invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the - * resolved method is used as basis for dispatch. - */ - public ResolutionResult resolveMethodOnClass(DexType holder, DexMethod method) { - assert checkIfObsolete(); - if (holder.isArrayType()) { - return resolveMethodOnArray(holder, method); - } - DexClass clazz = definitionFor(holder); - if (clazz == null) { - return ClassNotFoundResult.INSTANCE; - } - // Step 1: If holder is an interface, resolution fails with an ICCE. We return null. - if (clazz.isInterface()) { - return IncompatibleClassResult.INSTANCE; - } - return resolveMethodOnClass(clazz, method); - } - - public ResolutionResult resolveMethodOnClass(DexClass clazz, DexMethod method) { - assert checkIfObsolete(); - assert !clazz.isInterface(); - // Step 2: - ResolutionResult result = resolveMethodOnClassStep2(clazz, method, clazz); - if (result != null) { - return result; - } - // Finally Step 3: - return resolveMethodStep3(clazz, method); - } - - /** - * Implements step 2 of method resolution on classes as per <a - * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section - * 5.4.3.3 of the JVM Spec</a>. - */ - private ResolutionResult resolveMethodOnClassStep2( - DexClass clazz, DexMethod method, DexClass initialResolutionHolder) { - // Pt. 1: Signature polymorphic method check. - // See also <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9"> - // Section 2.9 of the JVM Spec</a>. - DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(method.name, dexItemFactory); - if (result != null) { - return new SingleResolutionResult(initialResolutionHolder, clazz, result); - } - // Pt 2: Find a method that matches the descriptor. - result = clazz.lookupMethod(method); - if (result != null) { - // If the resolved method is private, then it can only be accessed if the symbolic reference - // that initiated the resolution was the type at which the method resolved on. If that is not - // the case, then the error is either an IllegalAccessError, or in the case where access is - // allowed because of nests, a NoSuchMethodError. Which error cannot be determined without - // knowing the calling context. - if (result.isPrivateMethod() && clazz != initialResolutionHolder) { - return new IllegalAccessOrNoSuchMethodResult(result); - } - return new SingleResolutionResult(initialResolutionHolder, clazz, result); - } - // Pt 3: Apply step two to direct superclass of holder. - if (clazz.superType != null) { - DexClass superClass = definitionFor(clazz.superType); - if (superClass != null) { - return resolveMethodOnClassStep2(superClass, method, initialResolutionHolder); - } - } - return null; - } - - /** - * Implements step 3 of <a - * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section - * 5.4.3.3 of the JVM Spec</a>. As this is the same for interfaces and classes, we share one - * implementation. - */ - private ResolutionResult resolveMethodStep3(DexClass clazz, DexMethod method) { - MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); - resolveMethodStep3Helper(method, clazz, builder); - return builder.resolve(clazz); - } - - // Non-private lookup (ie, not resolution) to find interface targets. - DexClassAndMethod lookupMaximallySpecificTarget(DexClass clazz, DexMethod method) { - MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); - resolveMethodStep3Helper(method, clazz, builder); - return builder.lookup(); - } - - // Non-private lookup (ie, not resolution) to find interface targets. - DexClassAndMethod lookupMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) { - MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); - resolveMethodStep3Helper(method, dexItemFactory.objectType, lambda.interfaces, builder); - return builder.lookup(); - } - - /** Helper method that builds the set of maximally specific methods. */ - private void resolveMethodStep3Helper( - DexMethod method, DexClass clazz, MaximallySpecificMethodsBuilder builder) { - resolveMethodStep3Helper( - method, clazz.superType, Arrays.asList(clazz.interfaces.values), builder); - } - - private void resolveMethodStep3Helper( - DexMethod method, - DexType superType, - List<DexType> interfaces, - MaximallySpecificMethodsBuilder builder) { - for (DexType iface : interfaces) { - DexClass definiton = definitionFor(iface); - if (definiton == null) { - // Ignore missing interface definitions. - continue; - } - assert definiton.isInterface(); - DexEncodedMethod result = definiton.lookupMethod(method); - if (isMaximallySpecificCandidate(result)) { - // The candidate is added and doing so will prohibit shadowed methods from being in the set. - builder.addCandidate(definiton, result, this); - } else { - // Look at the super-interfaces of this class and keep searching. - resolveMethodStep3Helper(method, definiton, builder); - } - } - // Now look at indirect super interfaces. - if (superType != null) { - DexClass superClass = definitionFor(superType); - if (superClass != null) { - resolveMethodStep3Helper(method, superClass, builder); - } - } - } - - /** - * A candidate for being a maximally specific method must have neither its private, nor its static - * flag set. A candidate may still not be maximally specific, which entails that no subinterfaces - * from also contribute with a candidate to the type. That is not determined by this method. - */ - private boolean isMaximallySpecificCandidate(DexEncodedMethod method) { - return method != null && !method.accessFlags.isPrivate() && !method.accessFlags.isStatic(); - } - - /** - * Implements resolution of a method descriptor against an interface type. - * <p> - * See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3"> - * Section 5.4.3.4 of the JVM Spec</a>. - * <p> - * The resolved method is not the method that will actually be invoked. Which methods gets - * invoked depends on the invoke instruction used. However, it is always save to rewrite - * any invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the - * resolved method is used as basis for dispatch. - */ - public ResolutionResult resolveMethodOnInterface(DexType holder, DexMethod desc) { - assert checkIfObsolete(); - if (holder.isArrayType()) { - return IncompatibleClassResult.INSTANCE; - } - // Step 1: Lookup interface. - DexClass definition = definitionFor(holder); - // If the definition is not an interface, resolution fails with an ICCE. We just return the - // empty result here. - if (definition == null) { - return ClassNotFoundResult.INSTANCE; - } - if (!definition.isInterface()) { - return IncompatibleClassResult.INSTANCE; - } - return resolveMethodOnInterface(definition, desc); - } - - public ResolutionResult resolveMethodOnInterface(DexClass definition, DexMethod desc) { - assert checkIfObsolete(); - assert definition.isInterface(); - // Step 2: Look for exact method on interface. - DexEncodedMethod result = definition.lookupMethod(desc); - if (result != null) { - return new SingleResolutionResult(definition, definition, result); - } - // Step 3: Look for matching method on object class. - DexClass objectClass = definitionFor(dexItemFactory.objectType); - if (objectClass == null) { - return ClassNotFoundResult.INSTANCE; - } - result = objectClass.lookupMethod(desc); - if (result != null && result.accessFlags.isPublic() && !result.accessFlags.isAbstract()) { - return new SingleResolutionResult(definition, objectClass, result); - } - // Step 3: Look for maximally-specific superinterface methods or any interface definition. - // This is the same for classes and interfaces. - return resolveMethodStep3(definition, desc); - } - - /** - * Implements resolution of a field descriptor against the holder of the field. See also {@link - * #resolveFieldOn}. - */ - public DexEncodedField resolveField(DexField field) { - assert checkIfObsolete(); - return resolveFieldOn(field.holder, field); - } - - /** - * Implements resolution of a field descriptor against a type. - * <p> - * See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.2"> - * Section 5.4.3.2 of the JVM Spec</a>. - */ - public DexEncodedField resolveFieldOn(DexType type, DexField desc) { - assert checkIfObsolete(); - DexClass holder = definitionFor(type); - return holder != null ? resolveFieldOn(holder, desc) : null; - } - - public DexEncodedField resolveFieldOn(DexClass holder, DexField desc) { - assert checkIfObsolete(); - assert holder != null; - // Step 1: Class declares the field. - DexEncodedField result = holder.lookupField(desc); - if (result != null) { - return result; - } - // Step 2: Apply recursively to direct superinterfaces. First match succeeds. - for (DexType iface : holder.interfaces.values) { - result = resolveFieldOn(iface, desc); - if (result != null) { - return result; - } - } - // Step 3: Apply recursively to superclass. - if (holder.superType != null) { - result = resolveFieldOn(holder.superType, desc); - if (result != null) { - return result; - } - } - return null; - } - public boolean hasClassHierarchy() { assert checkIfObsolete(); return false; @@ -593,107 +272,19 @@ return app.mainDexList.contains(type); } - private static class MaximallySpecificMethodsBuilder { - - // The set of actual maximally specific methods. - // This set is linked map so that in the case where a number of methods remain a deterministic - // choice can be made. The map is from definition classes to their maximally specific method, or - // in the case that a type has a candidate which is shadowed by a subinterface, the map will - // map the class to a null entry, thus any addition to the map must check for key containment - // prior to writing. - LinkedHashMap<DexClass, DexEncodedMethod> maximallySpecificMethods = new LinkedHashMap<>(); - - void addCandidate(DexClass holder, DexEncodedMethod method, AppInfo appInfo) { - // If this candidate is already a candidate or it is shadowed, then no need to continue. - if (maximallySpecificMethods.containsKey(holder)) { - return; - } - maximallySpecificMethods.put(holder, method); - // Prune exiting candidates and prohibit future candidates in the super hierarchy. - assert holder.isInterface(); - assert holder.superType == appInfo.dexItemFactory.objectType; - for (DexType iface : holder.interfaces.values) { - markShadowed(iface, appInfo); - } - } - - private void markShadowed(DexType type, AppInfo appInfo) { - if (type == null) { - return; - } - DexClass clazz = appInfo.definitionFor(type); - if (clazz == null) { - return; - } - assert clazz.isInterface(); - assert clazz.superType == appInfo.dexItemFactory.objectType; - // A null entry signifies that the candidate is shadowed blocking future candidates. - // If the candidate is already shadowed at this type there is no need to shadow further up. - if (maximallySpecificMethods.containsKey(clazz) - && maximallySpecificMethods.get(clazz) == null) { - return; - } - maximallySpecificMethods.put(clazz, null); - for (DexType iface : clazz.interfaces.values) { - markShadowed(iface, appInfo); - } - } - - DexClassAndMethod lookup() { - SingleResolutionResult result = internalResolve(null).asSingleResolution(); - return result != null - ? DexClassAndMethod.create(result.getResolvedHolder(), result.getResolvedMethod()) - : null; - } - - ResolutionResult resolve(DexClass initialResolutionHolder) { - assert initialResolutionHolder != null; - return internalResolve(initialResolutionHolder); - } - - private ResolutionResult internalResolve(DexClass initialResolutionHolder) { - if (maximallySpecificMethods.isEmpty()) { - return NoSuchMethodResult.INSTANCE; - } - // Fast path in the common case of a single method. - if (maximallySpecificMethods.size() == 1) { - return singleResultHelper( - initialResolutionHolder, maximallySpecificMethods.entrySet().iterator().next()); - } - Entry<DexClass, DexEncodedMethod> firstMaximallySpecificMethod = null; - List<Entry<DexClass, DexEncodedMethod>> nonAbstractMethods = - new ArrayList<>(maximallySpecificMethods.size()); - for (Entry<DexClass, DexEncodedMethod> entry : maximallySpecificMethods.entrySet()) { - DexEncodedMethod method = entry.getValue(); - if (method == null) { - // Ignore shadowed candidates. - continue; - } - if (firstMaximallySpecificMethod == null) { - firstMaximallySpecificMethod = entry; - } - if (method.isNonAbstractVirtualMethod()) { - nonAbstractMethods.add(entry); - } - } - // If there are no non-abstract methods, then any candidate will suffice as a target. - // For deterministic resolution, we return the first mapped method (of the linked map). - if (nonAbstractMethods.isEmpty()) { - return singleResultHelper(initialResolutionHolder, firstMaximallySpecificMethod); - } - // If there is exactly one non-abstract method (a default method) it is the resolution target. - if (nonAbstractMethods.size() == 1) { - return singleResultHelper(initialResolutionHolder, nonAbstractMethods.get(0)); - } - return IncompatibleClassResult.create(ListUtils.map(nonAbstractMethods, Entry::getValue)); - } + public final FieldResolutionResult resolveField(DexField field, ProgramMethod context) { + return resolveFieldOn(field.holder, field, context); } - private static SingleResolutionResult singleResultHelper( - DexClass initialResolutionResult, Entry<DexClass, DexEncodedMethod> entry) { - return new SingleResolutionResult( - initialResolutionResult != null ? initialResolutionResult : entry.getKey(), - entry.getKey(), - entry.getValue()); + public FieldResolutionResult resolveFieldOn(DexType type, DexField field, ProgramMethod context) { + // Only allow resolution if the field is declared in the context. + if (type != context.getHolderType()) { + return FieldResolutionResult.failure(); + } + DexProgramClass clazz = context.getHolder(); + DexEncodedField definition = clazz.lookupField(field); + return definition != null + ? new SuccessfulFieldResolutionResult(clazz, clazz, definition) + : FieldResolutionResult.unknown(); } }
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java index 3d9e26c..a0fd03b 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -7,15 +7,27 @@ import static com.android.tools.r8.utils.TraversalContinuation.BREAK; import static com.android.tools.r8.utils.TraversalContinuation.CONTINUE; +import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult; +import com.android.tools.r8.graph.ResolutionResult.ArrayCloneMethodResult; +import com.android.tools.r8.graph.ResolutionResult.ClassNotFoundResult; +import com.android.tools.r8.graph.ResolutionResult.IllegalAccessOrNoSuchMethodResult; +import com.android.tools.r8.graph.ResolutionResult.IncompatibleClassResult; +import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult; +import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult; import com.android.tools.r8.ir.desugar.LambdaDescriptor; +import com.android.tools.r8.utils.ListUtils; +import com.android.tools.r8.utils.SetUtils; import com.android.tools.r8.utils.TraversalContinuation; import com.android.tools.r8.utils.WorkList; import com.google.common.collect.Sets; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Deque; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -30,10 +42,21 @@ super(application); } - public AppInfoWithClassHierarchy(AppInfo previous) { + // For desugaring. + private AppInfoWithClassHierarchy(AppInfo appInfo) { + super(appInfo); + } + + // For AppInfoWithLiveness. + protected AppInfoWithClassHierarchy(AppInfoWithClassHierarchy previous) { super(previous); } + public static AppInfoWithClassHierarchy createForDesugaring(AppInfo appInfo) { + assert !appInfo.hasClassHierarchy(); + return new AppInfoWithClassHierarchy(appInfo); + } + @Override public boolean hasClassHierarchy() { assert checkIfObsolete(); @@ -329,26 +352,34 @@ * <p>The result is the field that will be hit at runtime, if such field is known. A result of * null indicates that the field is either undefined or not an instance field. */ - public DexEncodedField lookupInstanceTarget(DexType type, DexField field) { + public DexEncodedField lookupInstanceTargetOn(DexType type, DexField field) { assert checkIfObsolete(); assert type.isClassType(); - DexEncodedField result = resolveFieldOn(type, field); + DexEncodedField result = resolveFieldOn(type, field).getResolvedField(); return result == null || result.accessFlags.isStatic() ? null : result; } + public DexEncodedField lookupInstanceTarget(DexField field) { + return lookupInstanceTargetOn(field.holder, field); + } + /** * Lookup static field starting in type and following the interface and super chain. * * <p>The result is the field that will be hit at runtime, if such field is known. A result of * null indicates that the field is either undefined or not a static field. */ - public DexEncodedField lookupStaticTarget(DexType type, DexField field) { + public DexEncodedField lookupStaticTargetOn(DexType type, DexField field) { assert checkIfObsolete(); assert type.isClassType(); - DexEncodedField result = resolveFieldOn(type, field); + DexEncodedField result = resolveFieldOn(type, field).getResolvedField(); return result == null || !result.accessFlags.isStatic() ? null : result; } + public DexEncodedField lookupStaticTarget(DexField field) { + return lookupStaticTargetOn(field.holder, field); + } + /** * Lookup static method following the super chain from the holder of {@code method}. * @@ -358,16 +389,15 @@ * @param method the method to lookup * @return The actual target for {@code method} or {@code null} if none found. */ - @Deprecated // TODO(b/147578480): Remove - public DexEncodedMethod lookupStaticTarget(DexMethod method, DexType invocationContext) { + // TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod(). + public DexEncodedMethod lookupStaticTarget(DexMethod method, DexProgramClass context) { assert checkIfObsolete(); - return lookupStaticTarget(method, toProgramClass(invocationContext)); + return unsafeResolveMethodDueToDexFormat(method).lookupInvokeStaticTarget(context, this); } - public final DexEncodedMethod lookupStaticTarget( - DexMethod method, DexProgramClass invocationContext) { - assert checkIfObsolete(); - return resolveMethod(method.holder, method).lookupInvokeStaticTarget(invocationContext, this); + // TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod(). + public DexEncodedMethod lookupStaticTarget(DexMethod method, ProgramMethod context) { + return lookupStaticTarget(method, context.getHolder()); } /** @@ -377,19 +407,18 @@ * non-null value if the result of resolution was an instance (i.e. non-static) method. * * @param method the method to lookup - * @param invocationContext the class the invoke is contained in, i.e., the holder of the caller. + * @param context the class the invoke is contained in, i.e., the holder of the caller. * @return The actual target for {@code method} or {@code null} if none found. */ - @Deprecated // TODO(b/147578480): Remove - public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) { + // TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod(). + public DexEncodedMethod lookupSuperTarget(DexMethod method, DexProgramClass context) { assert checkIfObsolete(); - return lookupSuperTarget(method, toProgramClass(invocationContext)); + return unsafeResolveMethodDueToDexFormat(method).lookupInvokeSuperTarget(context, this); } - public final DexEncodedMethod lookupSuperTarget( - DexMethod method, DexProgramClass invocationContext) { - assert checkIfObsolete(); - return resolveMethod(method.holder, method).lookupInvokeSuperTarget(invocationContext, this); + // TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod(). + public DexEncodedMethod lookupSuperTarget(DexMethod method, ProgramMethod context) { + return lookupSuperTarget(method, context.getHolder()); } /** @@ -400,14 +429,484 @@ * @param method the method to lookup * @return The actual target for {@code method} or {@code null} if none found. */ - @Deprecated // TODO(b/147578480): Remove - public DexEncodedMethod lookupDirectTarget(DexMethod method, DexType invocationContext) { + // TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod(). + public DexEncodedMethod lookupDirectTarget(DexMethod method, DexProgramClass context) { assert checkIfObsolete(); - return lookupDirectTarget(method, toProgramClass(invocationContext)); + return unsafeResolveMethodDueToDexFormat(method).lookupInvokeDirectTarget(context, this); } - public DexEncodedMethod lookupDirectTarget(DexMethod method, DexProgramClass invocationContext) { + // TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod(). + public DexEncodedMethod lookupDirectTarget(DexMethod method, ProgramMethod context) { + return lookupDirectTarget(method, context.getHolder()); + } + + /** + * Implements resolution of a method descriptor. + * + * <p>This method will query the definition of the holder to decide on which resolution to use. If + * the holder is an interface, it delegates to {@link #resolveMethodOnInterface(DexType, + * DexMethod)}, otherwise {@link #resolveMethodOnClass(DexMethod, DexType)} is used. + * + * <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the + * kind of a method reference. + */ + public ResolutionResult unsafeResolveMethodDueToDexFormat(DexMethod method) { assert checkIfObsolete(); - return resolveMethod(method.holder, method).lookupInvokeDirectTarget(invocationContext, this); + DexType holder = method.holder; + if (holder.isArrayType()) { + return resolveMethodOnArray(holder, method); + } + DexClass definition = definitionFor(holder); + if (definition == null) { + return ClassNotFoundResult.INSTANCE; + } + return resolveMethodOn(definition, method); + } + + public ResolutionResult resolveMethod(DexMethod method, boolean isInterface) { + return isInterface + ? resolveMethodOnInterface(method.holder, method) + : resolveMethodOnClass(method, method.holder); + } + + public ResolutionResult resolveMethodOn(DexClass holder, DexMethod method) { + return holder.isInterface() + ? resolveMethodOnInterface(holder, method) + : resolveMethodOnClass(method, holder); + } + + /** + * Implements resolution of a method descriptor against a target type. + * + * <p>The boolean isInterface parameter denotes if the method reference is an interface method + * reference, and if so method resolution is done according to interface method resolution. + * + * @param holder Type at which to initiate the resolution. + * @param method Method descriptor for resolution (the field method.holder is ignored). + * @param isInterface Indicates if resolution is to be done according to class or interface. + * @return The result of resolution. + */ + public ResolutionResult resolveMethodOn(DexType holder, DexMethod method, boolean isInterface) { + assert checkIfObsolete(); + return isInterface + ? resolveMethodOnInterface(holder, method) + : resolveMethodOnClass(method, holder); + } + + /** + * Implements resolution of a method descriptor against an array type. + * + * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">Section + * 10.7 of the Java Language Specification</a>. All invokations will have target java.lang.Object + * except clone which has no target. + */ + private ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) { + assert checkIfObsolete(); + assert holder.isArrayType(); + if (method.name == dexItemFactory().cloneMethodName) { + return ArrayCloneMethodResult.INSTANCE; + } else { + return resolveMethodOnClass(method, dexItemFactory().objectType); + } + } + + public ResolutionResult resolveMethodOnClass(DexMethod method) { + return resolveMethodOnClass(method, method.holder); + } + + /** + * Implements resolution of a method descriptor against a class type. + * + * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3"> + * Section 5.4.3.3 of the JVM Spec</a>. + * + * <p>The resolved method is not the method that will actually be invoked. Which methods gets + * invoked depends on the invoke instruction used. However, it is always safe to rewrite any + * invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the + * resolved method is used as basis for dispatch. + */ + public ResolutionResult resolveMethodOnClass(DexMethod method, DexType holder) { + assert checkIfObsolete(); + if (holder.isArrayType()) { + return resolveMethodOnArray(holder, method); + } + DexClass clazz = definitionFor(holder); + if (clazz == null) { + return ClassNotFoundResult.INSTANCE; + } + // Step 1: If holder is an interface, resolution fails with an ICCE. We return null. + if (clazz.isInterface()) { + return IncompatibleClassResult.INSTANCE; + } + return resolveMethodOnClass(method, clazz); + } + + public ResolutionResult resolveMethodOnClass(DexMethod method, DexClass clazz) { + assert checkIfObsolete(); + assert !clazz.isInterface(); + // Step 2: + ResolutionResult result = resolveMethodOnClassStep2(clazz, method, clazz); + if (result != null) { + return result; + } + // Finally Step 3: + return resolveMethodStep3(clazz, method); + } + + /** + * Implements step 2 of method resolution on classes as per <a + * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section + * 5.4.3.3 of the JVM Spec</a>. + */ + private ResolutionResult resolveMethodOnClassStep2( + DexClass clazz, DexMethod method, DexClass initialResolutionHolder) { + // Pt. 1: Signature polymorphic method check. + // See also <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9"> + // Section 2.9 of the JVM Spec</a>. + DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(method.name, dexItemFactory()); + if (result != null) { + return new SingleResolutionResult(initialResolutionHolder, clazz, result); + } + // Pt 2: Find a method that matches the descriptor. + result = clazz.lookupMethod(method); + if (result != null) { + // If the resolved method is private, then it can only be accessed if the symbolic reference + // that initiated the resolution was the type at which the method resolved on. If that is not + // the case, then the error is either an IllegalAccessError, or in the case where access is + // allowed because of nests, a NoSuchMethodError. Which error cannot be determined without + // knowing the calling context. + if (result.isPrivateMethod() && clazz != initialResolutionHolder) { + return new IllegalAccessOrNoSuchMethodResult(result); + } + return new SingleResolutionResult(initialResolutionHolder, clazz, result); + } + // Pt 3: Apply step two to direct superclass of holder. + if (clazz.superType != null) { + DexClass superClass = definitionFor(clazz.superType); + if (superClass != null) { + return resolveMethodOnClassStep2(superClass, method, initialResolutionHolder); + } + } + return null; + } + + /** + * Implements step 3 of <a + * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section + * 5.4.3.3 of the JVM Spec</a>. As this is the same for interfaces and classes, we share one + * implementation. + */ + private ResolutionResult resolveMethodStep3(DexClass clazz, DexMethod method) { + MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); + resolveMethodStep3Helper(method, clazz, builder); + return builder.resolve(clazz); + } + + // Non-private lookup (ie, not resolution) to find interface targets. + DexClassAndMethod lookupMaximallySpecificTarget(DexClass clazz, DexMethod method) { + MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); + resolveMethodStep3Helper(method, clazz, builder); + return builder.lookup(); + } + + // Non-private lookup (ie, not resolution) to find interface targets. + DexClassAndMethod lookupMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) { + MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); + resolveMethodStep3Helper(method, dexItemFactory().objectType, lambda.interfaces, builder); + return builder.lookup(); + } + + /** Helper method that builds the set of maximally specific methods. */ + private void resolveMethodStep3Helper( + DexMethod method, DexClass clazz, MaximallySpecificMethodsBuilder builder) { + resolveMethodStep3Helper( + method, clazz.superType, Arrays.asList(clazz.interfaces.values), builder); + } + + private void resolveMethodStep3Helper( + DexMethod method, + DexType superType, + List<DexType> interfaces, + MaximallySpecificMethodsBuilder builder) { + for (DexType iface : interfaces) { + DexClass definiton = definitionFor(iface); + if (definiton == null) { + // Ignore missing interface definitions. + continue; + } + assert definiton.isInterface(); + DexEncodedMethod result = definiton.lookupMethod(method); + if (isMaximallySpecificCandidate(result)) { + // The candidate is added and doing so will prohibit shadowed methods from being in the set. + builder.addCandidate(definiton, result, this); + } else { + // Look at the super-interfaces of this class and keep searching. + resolveMethodStep3Helper(method, definiton, builder); + } + } + // Now look at indirect super interfaces. + if (superType != null) { + DexClass superClass = definitionFor(superType); + if (superClass != null) { + resolveMethodStep3Helper(method, superClass, builder); + } + } + } + + /** + * A candidate for being a maximally specific method must have neither its private, nor its static + * flag set. A candidate may still not be maximally specific, which entails that no subinterfaces + * from also contribute with a candidate to the type. That is not determined by this method. + */ + private boolean isMaximallySpecificCandidate(DexEncodedMethod method) { + return method != null && !method.accessFlags.isPrivate() && !method.accessFlags.isStatic(); + } + + public ResolutionResult resolveMethodOnInterface(DexMethod method) { + return resolveMethodOnInterface(method.holder, method); + } + + /** + * Implements resolution of a method descriptor against an interface type. + * + * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3"> + * Section 5.4.3.4 of the JVM Spec</a>. + * + * <p>The resolved method is not the method that will actually be invoked. Which methods gets + * invoked depends on the invoke instruction used. However, it is always save to rewrite any + * invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the + * resolved method is used as basis for dispatch. + */ + public ResolutionResult resolveMethodOnInterface(DexType holder, DexMethod desc) { + assert checkIfObsolete(); + if (holder.isArrayType()) { + return IncompatibleClassResult.INSTANCE; + } + // Step 1: Lookup interface. + DexClass definition = definitionFor(holder); + // If the definition is not an interface, resolution fails with an ICCE. We just return the + // empty result here. + if (definition == null) { + return ClassNotFoundResult.INSTANCE; + } + if (!definition.isInterface()) { + return IncompatibleClassResult.INSTANCE; + } + return resolveMethodOnInterface(definition, desc); + } + + public ResolutionResult resolveMethodOnInterface(DexClass definition, DexMethod desc) { + assert checkIfObsolete(); + assert definition.isInterface(); + // Step 2: Look for exact method on interface. + DexEncodedMethod result = definition.lookupMethod(desc); + if (result != null) { + return new SingleResolutionResult(definition, definition, result); + } + // Step 3: Look for matching method on object class. + DexClass objectClass = definitionFor(dexItemFactory().objectType); + if (objectClass == null) { + return ClassNotFoundResult.INSTANCE; + } + result = objectClass.lookupMethod(desc); + if (result != null && result.accessFlags.isPublic() && !result.accessFlags.isAbstract()) { + return new SingleResolutionResult(definition, objectClass, result); + } + // Step 3: Look for maximally-specific superinterface methods or any interface definition. + // This is the same for classes and interfaces. + return resolveMethodStep3(definition, desc); + } + + /** + * Implements resolution of a field descriptor against the holder of the field. See also {@link + * #resolveFieldOn}. + */ + public FieldResolutionResult resolveField(DexField field) { + assert checkIfObsolete(); + return resolveFieldOn(field.holder, field); + } + + /** Intentionally drops {@param context} since this is only needed in D8. */ + @Override + public FieldResolutionResult resolveFieldOn(DexType type, DexField field, ProgramMethod context) { + return resolveFieldOn(type, field); + } + + /** + * Implements resolution of a field descriptor against a type. + * + * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.2"> + * Section 5.4.3.2 of the JVM Spec</a>. + */ + public FieldResolutionResult resolveFieldOn(DexType type, DexField field) { + assert checkIfObsolete(); + DexClass holder = definitionFor(type); + return holder != null ? resolveFieldOn(holder, field) : FieldResolutionResult.failure(); + } + + public FieldResolutionResult resolveFieldOn(DexClass holder, DexField field) { + assert checkIfObsolete(); + assert holder != null; + return resolveFieldOn(holder, field, holder, SetUtils.newIdentityHashSet(8)); + } + + private FieldResolutionResult resolveFieldOn( + DexClass holder, + DexField field, + DexClass initialResolutionHolder, + Set<DexType> visitedInterfaces) { + assert checkIfObsolete(); + assert holder != null; + // Step 1: Class declares the field. + DexEncodedField definition = holder.lookupField(field); + if (definition != null) { + return new SuccessfulFieldResolutionResult(initialResolutionHolder, holder, definition); + } + // Step 2: Apply recursively to direct superinterfaces. First match succeeds. + DexClassAndField result = resolveFieldOnDirectInterfaces(holder, field, visitedInterfaces); + if (result != null) { + return new SuccessfulFieldResolutionResult( + initialResolutionHolder, result.getHolder(), result.getDefinition()); + } + // Step 3: Apply recursively to superclass. + if (holder.superType != null) { + DexClass superClass = definitionFor(holder.superType); + if (superClass != null) { + return resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces); + } + } + return FieldResolutionResult.failure(); + } + + private DexClassAndField resolveFieldOnDirectInterfaces( + DexClass clazz, DexField field, Set<DexType> visitedInterfaces) { + for (DexType interfaceType : clazz.interfaces.values) { + if (visitedInterfaces.add(interfaceType)) { + DexClass interfaceClass = definitionFor(interfaceType); + if (interfaceClass != null) { + DexClassAndField result = + resolveFieldOnInterface(interfaceClass, field, visitedInterfaces); + if (result != null) { + return result; + } + } + } + } + return null; + } + + private DexClassAndField resolveFieldOnInterface( + DexClass interfaceClass, DexField field, Set<DexType> visitedInterfaces) { + // Step 1: Class declares the field. + DexEncodedField definition = interfaceClass.lookupField(field); + if (definition != null) { + return DexClassAndField.create(interfaceClass, definition); + } + // Step 2: Apply recursively to direct superinterfaces. First match succeeds. + return resolveFieldOnDirectInterfaces(interfaceClass, field, visitedInterfaces); + } + + private static class MaximallySpecificMethodsBuilder { + + // The set of actual maximally specific methods. + // This set is linked map so that in the case where a number of methods remain a deterministic + // choice can be made. The map is from definition classes to their maximally specific method, or + // in the case that a type has a candidate which is shadowed by a subinterface, the map will + // map the class to a null entry, thus any addition to the map must check for key containment + // prior to writing. + LinkedHashMap<DexClass, DexEncodedMethod> maximallySpecificMethods = new LinkedHashMap<>(); + + void addCandidate(DexClass holder, DexEncodedMethod method, AppInfo appInfo) { + // If this candidate is already a candidate or it is shadowed, then no need to continue. + if (maximallySpecificMethods.containsKey(holder)) { + return; + } + maximallySpecificMethods.put(holder, method); + // Prune exiting candidates and prohibit future candidates in the super hierarchy. + assert holder.isInterface(); + assert holder.superType == appInfo.dexItemFactory().objectType; + for (DexType iface : holder.interfaces.values) { + markShadowed(iface, appInfo); + } + } + + private void markShadowed(DexType type, AppInfo appInfo) { + if (type == null) { + return; + } + DexClass clazz = appInfo.definitionFor(type); + if (clazz == null) { + return; + } + assert clazz.isInterface(); + assert clazz.superType == appInfo.dexItemFactory().objectType; + // A null entry signifies that the candidate is shadowed blocking future candidates. + // If the candidate is already shadowed at this type there is no need to shadow further up. + if (maximallySpecificMethods.containsKey(clazz) + && maximallySpecificMethods.get(clazz) == null) { + return; + } + maximallySpecificMethods.put(clazz, null); + for (DexType iface : clazz.interfaces.values) { + markShadowed(iface, appInfo); + } + } + + DexClassAndMethod lookup() { + SingleResolutionResult result = internalResolve(null).asSingleResolution(); + return result != null + ? DexClassAndMethod.create(result.getResolvedHolder(), result.getResolvedMethod()) + : null; + } + + ResolutionResult resolve(DexClass initialResolutionHolder) { + assert initialResolutionHolder != null; + return internalResolve(initialResolutionHolder); + } + + private ResolutionResult internalResolve(DexClass initialResolutionHolder) { + if (maximallySpecificMethods.isEmpty()) { + return NoSuchMethodResult.INSTANCE; + } + // Fast path in the common case of a single method. + if (maximallySpecificMethods.size() == 1) { + return singleResultHelper( + initialResolutionHolder, maximallySpecificMethods.entrySet().iterator().next()); + } + Entry<DexClass, DexEncodedMethod> firstMaximallySpecificMethod = null; + List<Entry<DexClass, DexEncodedMethod>> nonAbstractMethods = + new ArrayList<>(maximallySpecificMethods.size()); + for (Entry<DexClass, DexEncodedMethod> entry : maximallySpecificMethods.entrySet()) { + DexEncodedMethod method = entry.getValue(); + if (method == null) { + // Ignore shadowed candidates. + continue; + } + if (firstMaximallySpecificMethod == null) { + firstMaximallySpecificMethod = entry; + } + if (method.isNonAbstractVirtualMethod()) { + nonAbstractMethods.add(entry); + } + } + // If there are no non-abstract methods, then any candidate will suffice as a target. + // For deterministic resolution, we return the first mapped method (of the linked map). + if (nonAbstractMethods.isEmpty()) { + return singleResultHelper(initialResolutionHolder, firstMaximallySpecificMethod); + } + // If there is exactly one non-abstract method (a default method) it is the resolution target. + if (nonAbstractMethods.size() == 1) { + return singleResultHelper(initialResolutionHolder, nonAbstractMethods.get(0)); + } + return IncompatibleClassResult.create(ListUtils.map(nonAbstractMethods, Entry::getValue)); + } + + private static SingleResolutionResult singleResultHelper( + DexClass initialResolutionResult, Entry<DexClass, DexEncodedMethod> entry) { + return new SingleResolutionResult( + initialResolutionResult != null ? initialResolutionResult : entry.getKey(), + entry.getKey(), + entry.getValue()); + } } }
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java index 484c3e1..a7c1351 100644 --- a/src/main/java/com/android/tools/r8/graph/AppView.java +++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -38,6 +38,7 @@ } private T appInfo; + private AppInfoWithClassHierarchy appInfoForDesugaring; private AppServices appServices; private final DexItemFactory dexItemFactory; private final WholeProgramOptimizations wholeProgramOptimizations; @@ -144,13 +145,31 @@ } public T appInfo() { + assert !appInfo.hasClassHierarchy() || enableWholeProgramOptimizations(); return appInfo; } + public AppInfoWithClassHierarchy appInfoForDesugaring() { + if (enableWholeProgramOptimizations()) { + assert appInfo.hasClassHierarchy(); + return appInfo.withClassHierarchy(); + } + assert !appInfo.hasClassHierarchy(); + if (appInfoForDesugaring == null) { + appInfoForDesugaring = AppInfoWithClassHierarchy.createForDesugaring(appInfo()); + } + return appInfoForDesugaring; + } + + private void unsetAppInfoForDesugaring() { + appInfoForDesugaring = null; + } + public <U extends T> AppView<U> setAppInfo(U appInfo) { assert !appInfo.isObsolete(); AppInfo previous = this.appInfo; this.appInfo = appInfo; + unsetAppInfoForDesugaring(); if (appInfo != previous) { previous.markObsolete(); } @@ -434,4 +453,9 @@ ? OptionalBool.of(appInfo().withLiveness().isSubtype(subtype, supertype)) : OptionalBool.unknown(); } + + public boolean isCfByteCodePassThrough(DexEncodedMethod method) { + return options.testing.cfByteCodePassThrough != null + && options.testing.cfByteCodePassThrough.test(method); + } }
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 b68b839..0b9b084 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -183,7 +183,7 @@ // Don't add parameter information if the code already has full debug information. // Note: This fast path can cause a method to loose its parameter info, if the debug info turned // out to be invalid during IR building. - if (appView.options().debug) { + if (appView.options().debug || appView.isCfByteCodePassThrough(method)) { return false; } assert localVariables.isEmpty(); @@ -395,23 +395,18 @@ @Override public void registerCodeReferences(ProgramMethod method, UseRegistry registry) { - internalRegisterCodeReferences(method, registry); + for (CfInstruction instruction : instructions) { + instruction.registerUse(registry, method); + } + tryCatchRanges.forEach(tryCatch -> tryCatch.guards.forEach(registry::registerTypeReference)); } @Override public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) { - internalRegisterCodeReferences(method, registry); - } - - private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) { for (CfInstruction instruction : instructions) { - instruction.registerUse(registry, method.getHolderType()); + instruction.registerUseForDesugaring(registry, method); } - for (CfTryCatch tryCatch : tryCatchRanges) { - for (DexType guard : tryCatch.guards) { - registry.registerTypeReference(guard); - } - } + tryCatchRanges.forEach(tryCatch -> tryCatch.guards.forEach(registry::registerTypeReference)); } @Override @@ -513,8 +508,7 @@ ProgramMethod method, AppView<AppInfoWithLiveness> appView, GraphLense graphLense, - DexType invocationContext) { - + DexProgramClass context) { InliningConstraints inliningConstraints = new InliningConstraints(appView, graphLense); if (appView.options().isInterfaceMethodDesugaringEnabled()) { // TODO(b/120130831): Conservatively need to say "no" at this point if there are invocations @@ -536,9 +530,7 @@ for (CfInstruction insn : instructions) { constraint = ConstraintWithTarget.meet( - constraint, - insn.inliningConstraint(inliningConstraints, invocationContext), - appView); + constraint, insn.inliningConstraint(inliningConstraints, context), appView); if (constraint == ConstraintWithTarget.NEVER) { return constraint; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java new file mode 100644 index 0000000..7b11467 --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -0,0 +1,78 @@ +// Copyright (c) 2020, 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.errors.Unreachable; +import com.android.tools.r8.origin.Origin; + +public class DexClassAndField { + + private final DexClass holder; + private final DexEncodedField field; + + DexClassAndField(DexClass holder, DexEncodedField field) { + assert holder != null; + assert field != null; + assert holder.type == field.holder(); + assert holder.isProgramClass() == (this instanceof ProgramField); + this.holder = holder; + this.field = field; + } + + public static DexClassAndField create(DexClass holder, DexEncodedField field) { + if (holder.isProgramClass()) { + return new ProgramField(holder.asProgramClass(), field); + } else { + return new DexClassAndField(holder, field); + } + } + + public DexClass getHolder() { + return holder; + } + + public DexType getHolderType() { + return holder.type; + } + + public DexEncodedField getDefinition() { + return field; + } + + public DexField getReference() { + return field.field; + } + + public Origin getOrigin() { + return holder.origin; + } + + public boolean isProgramField() { + return false; + } + + public ProgramField asProgramField() { + return null; + } + + public String toSourceString() { + return getReference().toSourceString(); + } + + @Override + public String toString() { + return toSourceString(); + } + + @Override + public boolean equals(Object object) { + throw new Unreachable("Unsupported attempt at comparing Class and DexClassAndField"); + } + + @Override + public int hashCode() { + throw new Unreachable("Unsupported attempt at computing the hashcode of DexClassAndField"); + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java index c589524..73395b2 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -231,7 +231,7 @@ } public boolean mayTriggerClassInitializationSideEffects( - AppView<AppInfoWithLiveness> appView, DexType context) { + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { // Only static field matters when it comes to class initialization side effects. if (!isStatic()) { return false; @@ -244,7 +244,7 @@ appView, // Types that are a super type of the current context are guaranteed to be initialized // already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.appInfo().isSubtype(context.getHolderType(), type), Sets.newIdentityHashSet())) { // Ignore class initialization side-effects for dead proto extension fields to ensure that // we force replace these field reads by null.
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java index b81c877..c2390fb 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -120,9 +120,6 @@ public static final DexEncodedMethod SENTINEL = new DexEncodedMethod( null, null, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), null); - public static final DexEncodedMethod ANNOTATION_REFERENCE = - new DexEncodedMethod( - null, null, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), null); public static final Int2ReferenceMap<DebugLocalInfo> NO_PARAMETER_INFO = new Int2ReferenceArrayMap<>(0);
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java index e27c7b4..900712b 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -175,10 +175,21 @@ return toProgramMethodOrNull(getInitializer(types)); } + public ProgramField lookupProgramField(DexField reference) { + return toProgramFieldOrNull(lookupField(reference)); + } + public ProgramMethod lookupProgramMethod(DexMethod reference) { return toProgramMethodOrNull(getMethodCollection().getMethod(reference)); } + private ProgramField toProgramFieldOrNull(DexEncodedField field) { + if (field != null) { + return new ProgramField(this, field); + } + return null; + } + private ProgramMethod toProgramMethodOrNull(DexEncodedMethod method) { if (method != null) { return new ProgramMethod(this, method);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java index 38d3a8e..35917f5 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java +++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.graph; -import java.util.Set; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; @@ -20,15 +20,15 @@ int getNumberOfWriteContexts(); - DexEncodedMethod getUniqueReadContext(); + ProgramMethod getUniqueReadContext(); void forEachIndirectAccess(Consumer<DexField> consumer); - void forEachIndirectAccessWithContexts(BiConsumer<DexField, Set<DexEncodedMethod>> consumer); + void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer); - void forEachReadContext(Consumer<DexEncodedMethod> consumer); + void forEachReadContext(Consumer<ProgramMethod> consumer); - void forEachWriteContext(Consumer<DexEncodedMethod> consumer); + void forEachWriteContext(Consumer<ProgramMethod> consumer); boolean hasReflectiveAccess(); @@ -38,17 +38,17 @@ boolean isRead(); - boolean isReadFromMethodHandle(); + boolean isReadFromAnnotation(); - boolean isReadOnlyIn(DexEncodedMethod method); + boolean isReadFromMethodHandle(); boolean isWritten(); boolean isWrittenFromMethodHandle(); - boolean isWrittenInMethodSatisfying(Predicate<DexEncodedMethod> predicate); + boolean isWrittenInMethodSatisfying(Predicate<ProgramMethod> predicate); - boolean isWrittenOnlyInMethodSatisfying(Predicate<DexEncodedMethod> predicate); + boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate); boolean isWrittenOutside(DexEncodedMethod method); }
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java index 5634d5b..9dd6c41 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java +++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
@@ -30,9 +30,10 @@ return infos.get(field); } - public void extend(DexField field, FieldAccessInfoImpl info) { + public FieldAccessInfoImpl extend(DexField field, FieldAccessInfoImpl info) { assert !infos.containsKey(field); infos.put(field, info); + return info; } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java index b15153b..383c6e2 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java +++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.graph; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.collect.Sets; import java.util.IdentityHashMap; import java.util.Map; @@ -22,9 +23,10 @@ public static final FieldAccessInfoImpl MISSING_FIELD_ACCESS_INFO = new FieldAccessInfoImpl(null); - public static int FLAG_IS_READ_FROM_METHOD_HANDLE = 1 << 0; - public static int FLAG_IS_WRITTEN_FROM_METHOD_HANDLE = 1 << 1; - public static int FLAG_HAS_REFLECTIVE_ACCESS = 1 << 2; + public static int FLAG_IS_READ_FROM_ANNOTATION = 1 << 0; + public static int FLAG_IS_READ_FROM_METHOD_HANDLE = 1 << 1; + public static int FLAG_IS_WRITTEN_FROM_METHOD_HANDLE = 1 << 2; + public static int FLAG_HAS_REFLECTIVE_ACCESS = 1 << 3; // A direct reference to the definition of the field. private DexField field; @@ -34,11 +36,11 @@ // Maps every direct and indirect reference in a read-context to the set of methods in which that // reference appears. - private Map<DexField, Set<DexEncodedMethod>> readsWithContexts; + private Map<DexField, ProgramMethodSet> readsWithContexts; // Maps every direct and indirect reference in a write-context to the set of methods in which that // reference appears. - private Map<DexField, Set<DexEncodedMethod>> writesWithContexts; + private Map<DexField, ProgramMethodSet> writesWithContexts; public FieldAccessInfoImpl(DexField field) { this.field = field; @@ -49,10 +51,10 @@ flattenAccessContexts(writesWithContexts); } - private void flattenAccessContexts(Map<DexField, Set<DexEncodedMethod>> accessesWithContexts) { + private void flattenAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) { if (accessesWithContexts != null) { - Set<DexEncodedMethod> flattenedAccessContexts = - accessesWithContexts.computeIfAbsent(field, ignore -> Sets.newIdentityHashSet()); + ProgramMethodSet flattenedAccessContexts = + accessesWithContexts.computeIfAbsent(field, ignore -> ProgramMethodSet.create()); accessesWithContexts.forEach( (access, contexts) -> { if (access != field) { @@ -87,7 +89,7 @@ return getNumberOfAccessContexts(writesWithContexts); } - private int getNumberOfAccessContexts(Map<DexField, Set<DexEncodedMethod>> accessesWithContexts) { + private int getNumberOfAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) { if (accessesWithContexts == null) { return 0; } @@ -98,9 +100,9 @@ } @Override - public DexEncodedMethod getUniqueReadContext() { + public ProgramMethod getUniqueReadContext() { if (readsWithContexts != null && readsWithContexts.size() == 1) { - Set<DexEncodedMethod> contexts = readsWithContexts.values().iterator().next(); + ProgramMethodSet contexts = readsWithContexts.values().iterator().next(); if (contexts.size() == 1) { return contexts.iterator().next(); } @@ -120,7 +122,7 @@ } private static void forEachAccessInMap( - Map<DexField, Set<DexEncodedMethod>> accessesWithContexts, + Map<DexField, ProgramMethodSet> accessesWithContexts, Predicate<DexField> predicate, Consumer<DexField> consumer) { if (accessesWithContexts != null) { @@ -134,9 +136,8 @@ } @Override - public void forEachIndirectAccessWithContexts( - BiConsumer<DexField, Set<DexEncodedMethod>> consumer) { - Map<DexField, Set<DexEncodedMethod>> indirectAccessesWithContexts = new IdentityHashMap<>(); + public void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer) { + Map<DexField, ProgramMethodSet> indirectAccessesWithContexts = new IdentityHashMap<>(); extendAccessesWithContexts( indirectAccessesWithContexts, access -> access != field, readsWithContexts); extendAccessesWithContexts( @@ -145,15 +146,15 @@ } private void extendAccessesWithContexts( - Map<DexField, Set<DexEncodedMethod>> accessesWithContexts, + Map<DexField, ProgramMethodSet> accessesWithContexts, Predicate<DexField> predicate, - Map<DexField, Set<DexEncodedMethod>> extension) { + Map<DexField, ProgramMethodSet> extension) { if (extension != null) { extension.forEach( (access, contexts) -> { if (predicate.test(access)) { accessesWithContexts - .computeIfAbsent(access, ignore -> Sets.newIdentityHashSet()) + .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) .addAll(contexts); } }); @@ -161,24 +162,23 @@ } @Override - public void forEachReadContext(Consumer<DexEncodedMethod> consumer) { + public void forEachReadContext(Consumer<ProgramMethod> consumer) { forEachAccessContext(readsWithContexts, consumer); } @Override - public void forEachWriteContext(Consumer<DexEncodedMethod> consumer) { + public void forEachWriteContext(Consumer<ProgramMethod> consumer) { forEachAccessContext(writesWithContexts, consumer); } private void forEachAccessContext( - Map<DexField, Set<DexEncodedMethod>> accessesWithContexts, - Consumer<DexEncodedMethod> consumer) { + Map<DexField, ProgramMethodSet> accessesWithContexts, Consumer<ProgramMethod> consumer) { // There can be indirect reads and writes of the same field reference, so we need to keep track // of the previously-seen indirect accesses to avoid reporting duplicates. - Set<DexEncodedMethod> visited = Sets.newIdentityHashSet(); + ProgramMethodSet visited = ProgramMethodSet.create(); if (accessesWithContexts != null) { - for (Set<DexEncodedMethod> encodedAccessContexts : accessesWithContexts.values()) { - for (DexEncodedMethod encodedAccessContext : encodedAccessContexts) { + for (ProgramMethodSet encodedAccessContexts : accessesWithContexts.values()) { + for (ProgramMethod encodedAccessContext : encodedAccessContexts) { if (visited.add(encodedAccessContext)) { consumer.accept(encodedAccessContext); } @@ -199,7 +199,16 @@ /** Returns true if this field is read by the program. */ @Override public boolean isRead() { - return readsWithContexts != null && !readsWithContexts.isEmpty(); + return (readsWithContexts != null && !readsWithContexts.isEmpty()) || isReadFromAnnotation(); + } + + @Override + public boolean isReadFromAnnotation() { + return (flags & FLAG_IS_READ_FROM_ANNOTATION) != 0; + } + + public void setReadFromAnnotation() { + flags |= FLAG_IS_READ_FROM_ANNOTATION; } @Override @@ -211,14 +220,6 @@ flags |= FLAG_IS_READ_FROM_METHOD_HANDLE; } - @Override - public boolean isReadOnlyIn(DexEncodedMethod method) { - assert isRead(); - assert method != null; - DexEncodedMethod uniqueReadContext = getUniqueReadContext(); - return uniqueReadContext != null && uniqueReadContext == method; - } - /** Returns true if this field is written by the program. */ @Override public boolean isWritten() { @@ -238,10 +239,10 @@ * Returns true if this field is written by a method for which {@param predicate} returns true. */ @Override - public boolean isWrittenInMethodSatisfying(Predicate<DexEncodedMethod> predicate) { + public boolean isWrittenInMethodSatisfying(Predicate<ProgramMethod> predicate) { if (writesWithContexts != null) { - for (Set<DexEncodedMethod> encodedWriteContexts : writesWithContexts.values()) { - for (DexEncodedMethod encodedWriteContext : encodedWriteContexts) { + for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) { + for (ProgramMethod encodedWriteContext : encodedWriteContexts) { if (predicate.test(encodedWriteContext)) { return true; } @@ -256,10 +257,10 @@ * true. */ @Override - public boolean isWrittenOnlyInMethodSatisfying(Predicate<DexEncodedMethod> predicate) { + public boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) { if (writesWithContexts != null) { - for (Set<DexEncodedMethod> encodedWriteContexts : writesWithContexts.values()) { - for (DexEncodedMethod encodedWriteContext : encodedWriteContexts) { + for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) { + for (ProgramMethod encodedWriteContext : encodedWriteContexts) { if (!predicate.test(encodedWriteContext)) { return false; } @@ -275,9 +276,9 @@ @Override public boolean isWrittenOutside(DexEncodedMethod method) { if (writesWithContexts != null) { - for (Set<DexEncodedMethod> encodedWriteContexts : writesWithContexts.values()) { - for (DexEncodedMethod encodedWriteContext : encodedWriteContexts) { - if (encodedWriteContext != method) { + for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) { + for (ProgramMethod encodedWriteContext : encodedWriteContexts) { + if (encodedWriteContext.getDefinition() != method) { return true; } } @@ -286,21 +287,21 @@ return false; } - public boolean recordRead(DexField access, DexEncodedMethod context) { + public boolean recordRead(DexField access, ProgramMethod context) { if (readsWithContexts == null) { readsWithContexts = new IdentityHashMap<>(); } return readsWithContexts - .computeIfAbsent(access, ignore -> Sets.newIdentityHashSet()) + .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) .add(context); } - public boolean recordWrite(DexField access, DexEncodedMethod context) { + public boolean recordWrite(DexField access, ProgramMethod context) { if (writesWithContexts == null) { writesWithContexts = new IdentityHashMap<>(); } return writesWithContexts - .computeIfAbsent(access, ignore -> Sets.newIdentityHashSet()) + .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) .add(context); } @@ -319,11 +320,11 @@ rewritten.readsWithContexts = new IdentityHashMap<>(); readsWithContexts.forEach( (access, contexts) -> { - Set<DexEncodedMethod> newContexts = + ProgramMethodSet newContexts = rewritten.readsWithContexts.computeIfAbsent( - lens.lookupField(access), ignore -> Sets.newIdentityHashSet()); - for (DexEncodedMethod context : contexts) { - newContexts.add(lens.mapDexEncodedMethod(context, definitions)); + lens.lookupField(access), ignore -> ProgramMethodSet.create()); + for (ProgramMethod context : contexts) { + newContexts.add(lens.mapProgramMethod(context, definitions)); } }); } @@ -331,11 +332,11 @@ rewritten.writesWithContexts = new IdentityHashMap<>(); writesWithContexts.forEach( (access, contexts) -> { - Set<DexEncodedMethod> newContexts = + ProgramMethodSet newContexts = rewritten.writesWithContexts.computeIfAbsent( - lens.lookupField(access), ignore -> Sets.newIdentityHashSet()); - for (DexEncodedMethod context : contexts) { - newContexts.add(lens.mapDexEncodedMethod(context, definitions)); + lens.lookupField(access), ignore -> ProgramMethodSet.create()); + for (ProgramMethod context : contexts) { + newContexts.add(lens.mapProgramMethod(context, definitions)); } }); }
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java new file mode 100644 index 0000000..e5d7239 --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -0,0 +1,115 @@ +// Copyright (c) 2020, 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.utils.OptionalBool; + +public abstract class FieldResolutionResult { + + public static FailedFieldResolutionResult failure() { + return FailedFieldResolutionResult.INSTANCE; + } + + public static UnknownFieldResolutionResult unknown() { + return UnknownFieldResolutionResult.INSTANCE; + } + + public DexEncodedField getResolvedField() { + return null; + } + + public abstract OptionalBool isAccessibleFrom( + ProgramMethod context, AppInfoWithClassHierarchy appInfo); + + public boolean isSuccessfulResolution() { + return false; + } + + public SuccessfulFieldResolutionResult asSuccessfulResolution() { + return null; + } + + public boolean isFailedOrUnknownResolution() { + return false; + } + + public static class SuccessfulFieldResolutionResult extends FieldResolutionResult { + + private final DexClass initialResolutionHolder; + private final DexClass resolvedHolder; + private final DexEncodedField resolvedField; + + SuccessfulFieldResolutionResult( + DexClass initialResolutionHolder, DexClass resolvedHolder, DexEncodedField resolvedField) { + assert resolvedHolder.type == resolvedField.holder(); + this.initialResolutionHolder = initialResolutionHolder; + this.resolvedHolder = resolvedHolder; + this.resolvedField = resolvedField; + } + + public DexClass getResolvedHolder() { + return resolvedHolder; + } + + @Override + public DexEncodedField getResolvedField() { + return resolvedField; + } + + public DexClassAndField getResolutionPair() { + return DexClassAndField.create(resolvedHolder, resolvedField); + } + + @Override + public OptionalBool isAccessibleFrom(ProgramMethod context, AppInfoWithClassHierarchy appInfo) { + return AccessControl.isFieldAccessible( + resolvedField, initialResolutionHolder, context.getHolder(), appInfo); + } + + @Override + public boolean isSuccessfulResolution() { + return true; + } + + @Override + public SuccessfulFieldResolutionResult asSuccessfulResolution() { + return this; + } + } + + public static class FailedFieldResolutionResult extends FieldResolutionResult { + + private static final FailedFieldResolutionResult INSTANCE = new FailedFieldResolutionResult(); + + @Override + public OptionalBool isAccessibleFrom(ProgramMethod context, AppInfoWithClassHierarchy appInfo) { + return OptionalBool.FALSE; + } + + @Override + public boolean isFailedOrUnknownResolution() { + return true; + } + } + + /** + * Used in D8 when trying to resolve a field that is not declared on the enclosing class of the + * current method. + */ + public static class UnknownFieldResolutionResult extends FieldResolutionResult { + + private static final UnknownFieldResolutionResult INSTANCE = new UnknownFieldResolutionResult(); + + @Override + public OptionalBool isAccessibleFrom(ProgramMethod context, AppInfoWithClassHierarchy appInfo) { + return OptionalBool.FALSE; + } + + @Override + public boolean isFailedOrUnknownResolution() { + return true; + } + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java index e5de7ff..2a5f317 100644 --- a/src/main/java/com/android/tools/r8/graph/GraphLense.java +++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -145,9 +145,6 @@ public DexEncodedMethod mapDexEncodedMethod( DexEncodedMethod originalEncodedMethod, DexDefinitionSupplier definitions) { assert originalEncodedMethod != DexEncodedMethod.SENTINEL; - if (originalEncodedMethod == DexEncodedMethod.ANNOTATION_REFERENCE) { - return DexEncodedMethod.ANNOTATION_REFERENCE; - } DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.method); // Note that: // * Even if `newMethod` is the same as `originalEncodedMethod.method`, we still need to look it @@ -161,6 +158,13 @@ return newEncodedMethod; } + public ProgramMethod mapProgramMethod( + ProgramMethod oldMethod, DexDefinitionSupplier definitions) { + DexMethod newMethod = getRenamedMethodSignature(oldMethod.getReference()); + DexProgramClass holder = definitions.definitionForHolder(newMethod).asProgramClass(); + return holder.lookupProgramMethod(newMethod); + } + public abstract DexType lookupType(DexType type); // This overload can be used when the graph lense is known to be context insensitive.
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java new file mode 100644 index 0000000..29949d8 --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -0,0 +1,33 @@ +// Copyright (c) 2020, 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; + +public class ProgramField extends DexClassAndField { + + public ProgramField(DexProgramClass holder, DexEncodedField field) { + super(holder, field); + } + + public boolean isStructurallyEqualTo(ProgramField other) { + return getDefinition() == other.getDefinition() && getHolder() == other.getHolder(); + } + + @Override + public boolean isProgramField() { + return true; + } + + @Override + public ProgramField asProgramField() { + return this; + } + + @Override + public DexProgramClass getHolder() { + DexClass holder = super.getHolder(); + assert holder.isProgramClass(); + return holder.asProgramClass(); + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java index fd1781d..fab752df 100644 --- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java +++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -62,6 +62,11 @@ public abstract OptionalBool isAccessibleFrom( DexProgramClass context, AppInfoWithClassHierarchy appInfo); + public final OptionalBool isAccessibleFrom( + ProgramMethod context, AppInfoWithClassHierarchy appInfo) { + return isAccessibleFrom(context.getHolder(), appInfo); + } + public abstract OptionalBool isAccessibleForVirtualDispatchFrom( DexProgramClass context, AppInfoWithClassHierarchy appInfo); @@ -228,12 +233,12 @@ * result of resolution was a static, non-abstract method. * * @param context Class the invoke is contained in, i.e., the holder of the caller. - * * @param appInfo Application info. + * @param appInfo Application info. * @return The actual target or {@code null} if none found. */ @Override - public DexEncodedMethod lookupInvokeStaticTarget(DexProgramClass context, - AppInfoWithClassHierarchy appInfo) { + public DexEncodedMethod lookupInvokeStaticTarget( + DexProgramClass context, AppInfoWithClassHierarchy appInfo) { if (isAccessibleFrom(context, appInfo).isFalse()) { return null; } @@ -265,7 +270,7 @@ } private DexEncodedMethod internalInvokeSpecialOrSuper( - DexClass context, + DexProgramClass context, AppInfoWithClassHierarchy appInfo, BiPredicate<DexClass, DexClass> isSuperclass) { @@ -669,8 +674,8 @@ } @Override - public DexEncodedMethod lookupInvokeStaticTarget(DexProgramClass context, - AppInfoWithClassHierarchy appInfo) { + public DexEncodedMethod lookupInvokeStaticTarget( + DexProgramClass context, AppInfoWithClassHierarchy appInfo) { return null; }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java index 06f544d..049e211 100644 --- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java +++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -4,8 +4,9 @@ package com.android.tools.r8.graph.analysis; -import com.android.tools.r8.graph.DexEncodedField; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.shaking.Enqueuer; import com.android.tools.r8.shaking.EnqueuerWorklist; @@ -17,10 +18,11 @@ public void processNewlyInstantiatedClass(DexProgramClass clazz, ProgramMethod context) {} /** Called when a class is found to be live. */ - public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {} + public void processNewlyLiveClass( + DexProgramClass clazz, EnqueuerWorklist worklist, DexDefinitionSupplier definitionSupplier) {} /** Called when a field is found to be live. */ - public void processNewlyLiveField(DexEncodedField field) {} + public void processNewlyLiveField(ProgramField field) {} /** Called when a method is found to be live. */ public void processNewlyLiveMethod(ProgramMethod method) {}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java index 48518f5..59c37b8 100644 --- a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java +++ b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
@@ -6,7 +6,6 @@ import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.ProgramMethod; @@ -28,25 +27,26 @@ this.mapping = mapping; } - public boolean isClassDefinitelyLoadedInInstanceMethodsOn(DexType subject, DexType context) { + public boolean isClassDefinitelyLoadedInInstanceMethod( + DexProgramClass subject, ProgramMethod context) { + assert !context.getDefinition().isStatic(); // If `subject` is kept, then it is instantiated by reflection, which means that the analysis // has not seen all allocation sites. In that case, we conservatively return false. AppInfoWithClassHierarchy appInfo = appView.appInfo(); - if (appInfo.hasLiveness() && appInfo.withLiveness().isPinned(subject)) { + if (appInfo.hasLiveness() && appInfo.withLiveness().isPinned(subject.type)) { return false; } // Check that `subject` is guaranteed to be initialized in all instance methods of `context`. DexType guaranteedToBeInitializedInContext = - mapping.getOrDefault(context, appView.dexItemFactory().objectType); - if (!appInfo.isSubtype(guaranteedToBeInitializedInContext, subject)) { + mapping.getOrDefault(context.getHolderType(), appView.dexItemFactory().objectType); + if (!appInfo.isSubtype(guaranteedToBeInitializedInContext, subject.type)) { return false; } // Also check that `subject` is not an interface, since interfaces are not initialized // transitively. - DexClass clazz = appView.definitionFor(subject); - return clazz != null && !clazz.isInterface(); + return !subject.isInterface(); } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java index e825ba4..978646c 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -10,9 +10,9 @@ import com.android.tools.r8.graph.DexDefinition; import com.android.tools.r8.graph.DexEncodedField; 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.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.code.BasicBlock; @@ -74,7 +74,6 @@ private final AppView<AppInfoWithLiveness> appView; private final IRCode code; - private final DexItemFactory dexItemFactory; private DominatorTree dominatorTree = null; private int markingColor = -1; @@ -82,13 +81,11 @@ private ClassInitializationAnalysis() { this.appView = null; this.code = null; - this.dexItemFactory = null; } public ClassInitializationAnalysis(AppView<AppInfoWithLiveness> appView, IRCode code) { this.appView = appView; this.code = code; - this.dexItemFactory = appView.dexItemFactory(); } // Returns a trivial, conservative analysis that always returns false. @@ -97,7 +94,7 @@ } public boolean isClassDefinitelyLoadedBeforeInstruction(DexType type, Instruction instruction) { - DexType context = code.method().holder(); + ProgramMethod context = code.context(); BasicBlock block = instruction.getBlock(); // Visit the instructions in `block` prior to `instruction`. @@ -237,7 +234,7 @@ public static boolean forInitClass( InitClass instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -251,7 +248,7 @@ public static boolean forInstanceGet( InstanceGet instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return forInstanceGetOrPut(instruction, type, appView, mode, assumption); @@ -260,7 +257,7 @@ public static boolean forInstancePut( InstancePut instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return forInstanceGetOrPut(instruction, type, appView, mode, assumption); @@ -269,7 +266,7 @@ private static boolean forInstanceGetOrPut( FieldInstruction instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { assert instruction.isInstanceGet() || instruction.isInstancePut(); @@ -283,14 +280,15 @@ return false; } } - DexEncodedField field = appView.appInfo().resolveField(instruction.getField()); + DexEncodedField field = + appView.appInfo().resolveField(instruction.getField()).getResolvedField(); return field != null && isTypeInitializedBy(instruction, type, field, appView, mode); } public static boolean forInvokeDirect( InvokeDirect instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -306,8 +304,8 @@ public static boolean forInvokeInterface( InvokeInterface instruction, DexType type, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -342,8 +340,8 @@ public static boolean forInvokeStatic( InvokeStatic instruction, DexType type, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -357,8 +355,8 @@ public static boolean forInvokeSuper( InvokeSuper instruction, DexType type, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -390,7 +388,7 @@ return false; } ResolutionResult resolutionResult = - appView.appInfo().resolveMethod(superType, method, instruction.itf); + appView.appInfo().resolveMethodOn(superType, method, instruction.itf); if (!resolutionResult.isSingleResolution()) { return false; } @@ -401,8 +399,8 @@ public static boolean forInvokeVirtual( InvokeVirtual instruction, DexType type, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -426,7 +424,7 @@ } DexMethod method = instruction.getInvokedMethod(); ResolutionResult resolutionResult = - appView.appInfo().resolveMethodOnClass(method.holder, method); + appView.appInfo().resolveMethodOnClass(method, method.holder); if (!resolutionResult.isSingleResolution()) { return false; } @@ -437,7 +435,7 @@ public static boolean forNewInstance( NewInstance instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { if (assumption == AnalysisAssumption.NONE) { @@ -451,7 +449,7 @@ public static boolean forStaticGet( StaticGet instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return forStaticGetOrPut(instruction, type, appView, mode, assumption); @@ -460,7 +458,7 @@ public static boolean forStaticPut( StaticPut instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return forStaticGetOrPut(instruction, type, appView, mode, assumption); @@ -469,7 +467,7 @@ private static boolean forStaticGetOrPut( FieldInstruction instruction, DexType type, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { assert instruction.isStaticGet() || instruction.isStaticPut(); @@ -477,7 +475,8 @@ // Class initialization may fail with ExceptionInInitializerError. return false; } - DexEncodedField field = appView.appInfo().resolveField(instruction.getField()); + DexEncodedField field = + appView.appInfo().resolveField(instruction.getField()).getResolvedField(); return field != null && isTypeInitializedBy(instruction, type, field, appView, mode); } @@ -485,7 +484,7 @@ Instruction instruction, DexType typeToBeInitialized, DexDefinition definition, - AppView<?> appView, + AppView<AppInfoWithLiveness> appView, Query mode) { if (mode == Query.DIRECTLY) { if (definition.isDexClass()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java index 5452f50..32c1bb1 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java
@@ -37,7 +37,7 @@ } if (instr.isInvokeMethod()) { DexEncodedMethod target = - instr.asInvokeMethod().lookupSingleTarget(appView, code.method().holder()); + instr.asInvokeMethod().lookupSingleTarget(appView, code.context()); if (target != null && target.getOptimizationInfo().returnValueOnlyDependsOnArguments()) { continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java index 215f2a1..b73a496 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; 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.BasicBlock; import com.android.tools.r8.ir.code.DefaultInstructionVisitor; import com.android.tools.r8.ir.code.DominatorTree; @@ -36,7 +37,7 @@ public static Set<DexType> computeInitializedClassesOnNormalExit( AppView<AppInfoWithLiveness> appView, IRCode code) { DominatorTree dominatorTree = new DominatorTree(code, Assumption.MAY_HAVE_UNREACHABLE_BLOCKS); - Visitor visitor = new Visitor(appView, code.method().holder()); + Visitor visitor = new Visitor(appView, code.context()); for (BasicBlock dominator : dominatorTree.normalExitDominatorBlocks()) { if (dominator.hasCatchHandlers()) { // When determining which classes that are guaranteed to be initialized from a given @@ -55,10 +56,10 @@ private static class Visitor extends DefaultInstructionVisitor<Void> { private final AppView<AppInfoWithLiveness> appView; - private final DexType context; + private final ProgramMethod context; private final Set<DexType> initializedClassesOnNormalExit = Sets.newIdentityHashSet(); - Visitor(AppView<AppInfoWithLiveness> appView, DexType context) { + Visitor(AppView<AppInfoWithLiveness> appView, ProgramMethod context) { this.appView = appView; this.context = context; } @@ -72,7 +73,7 @@ } private void markInitializedOnNormalExit(DexType knownToBeInitialized) { - if (knownToBeInitialized == context) { + if (knownToBeInitialized == context.getHolderType()) { // Do not record that the given method causes its own holder to be initialized, since this // is trivial. return; @@ -113,7 +114,8 @@ @Override public Void handleFieldInstruction(FieldInstruction instruction) { - DexEncodedField field = appView.appInfo().resolveField(instruction.getField()); + DexEncodedField field = + appView.appInfo().resolveField(instruction.getField()).getResolvedField(); if (field != null) { if (field.holder().isClassType()) { markInitializedOnNormalExit(field.holder());
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java index fbb6735..82e53b7 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
@@ -10,7 +10,7 @@ import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.code.ArrayPut; import com.android.tools.r8.ir.code.IRCode; @@ -27,8 +27,6 @@ import com.android.tools.r8.utils.LongInterval; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; -import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -69,19 +67,15 @@ private final AppView<?> appView; private final IRCode code; - private final DexType context; + private final ProgramMethod context; private final Set<Value> knownNotToDependOnEnvironment = Sets.newIdentityHashSet(); private final Set<Value> visited = Sets.newIdentityHashSet(); - // Lazily computed mapping from final field definitions of the enclosing class to the static-put - // instructions in the class initializer that assigns these final fields. - private Map<DexEncodedField, List<StaticPut>> finalFieldPuts; - public ValueMayDependOnEnvironmentAnalysis(AppView<?> appView, IRCode code) { this.appView = appView; this.code = code; - this.context = code.method().holder(); + this.context = code.context(); } public boolean valueMayDependOnEnvironment(Value value) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java b/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java index 27c4e19..e4235e6 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
@@ -8,7 +8,7 @@ import static com.google.common.base.Predicates.or; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.BasicBlock; import com.android.tools.r8.ir.code.ConstClass; import com.android.tools.r8.ir.code.ConstNumber; @@ -33,9 +33,9 @@ public class BasicBlockBehavioralSubsumption { private final AppView<?> appView; - private final DexType context; + private final ProgramMethod context; - public BasicBlockBehavioralSubsumption(AppView<?> appView, DexType context) { + public BasicBlockBehavioralSubsumption(AppView<?> appView, ProgramMethod context) { this.appView = appView; this.context = context; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/escape/DefaultEscapeAnalysisConfiguration.java b/src/main/java/com/android/tools/r8/ir/analysis/escape/DefaultEscapeAnalysisConfiguration.java index 6ec09bb..b65eda2 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/escape/DefaultEscapeAnalysisConfiguration.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/escape/DefaultEscapeAnalysisConfiguration.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.ir.analysis.escape; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Instruction; public class DefaultEscapeAnalysisConfiguration implements EscapeAnalysisConfiguration { @@ -24,7 +24,7 @@ AppView<?> appView, EscapeAnalysis escapeAnalysis, Instruction escapeRoute, - DexMethod context) { + ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysis.java index b1cac80..b1821c3 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysis.java
@@ -5,6 +5,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.BasicBlock; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Instruction; @@ -137,8 +138,8 @@ } } } - if (!configuration.isLegitimateEscapeRoute(appView, this, user, code.method().method) - && isDirectlyEscaping(user, code.method().method, arguments)) { + if (!configuration.isLegitimateEscapeRoute(appView, this, user, code.context()) + && isDirectlyEscaping(user, code.context(), arguments)) { if (stoppingCriterion.test(user)) { return true; } @@ -173,7 +174,8 @@ } } - private boolean isDirectlyEscaping(Instruction instr, DexMethod context, List<Value> arguments) { + private boolean isDirectlyEscaping( + Instruction instr, ProgramMethod context, List<Value> arguments) { // As return value. if (instr.isReturn()) { return true; @@ -190,7 +192,7 @@ if (instr.isInvokeMethod()) { DexMethod invokedMethod = instr.asInvokeMethod().getInvokedMethod(); // Filter out the recursion with exactly same arguments. - if (invokedMethod == context) { + if (invokedMethod == context.getReference()) { return !instr.inValues().equals(arguments); } return true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisConfiguration.java b/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisConfiguration.java index ea3a7e3..e3e5f4b 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisConfiguration.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisConfiguration.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.ir.analysis.escape; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Instruction; public interface EscapeAnalysisConfiguration { @@ -14,5 +14,5 @@ AppView<?> appView, EscapeAnalysis escapeAnalysis, Instruction escapeRoute, - DexMethod context); + ProgramMethod context); }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java index 7c148a4..015b182 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
@@ -6,9 +6,11 @@ import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.FieldResolutionResult; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.ir.code.FieldInstruction; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Instruction; @@ -21,7 +23,7 @@ public class FieldAccessAnalysis { - private final AppView<?> appView; + private final AppView<? extends AppInfoWithClassHierarchy> appView; private final FieldAssignmentTracker fieldAssignmentTracker; private final FieldBitAccessAnalysis fieldBitAccessAnalysis; @@ -35,7 +37,7 @@ } public FieldAccessAnalysis( - AppView<?> appView, + AppView<? extends AppInfoWithClassHierarchy> appView, FieldAssignmentTracker fieldAssignmentTracker, FieldBitAccessAnalysis fieldBitAccessAnalysis) { this.appView = appView; @@ -71,13 +73,20 @@ for (Instruction instruction : code.instructions()) { if (instruction.isFieldInstruction()) { FieldInstruction fieldInstruction = instruction.asFieldInstruction(); - DexEncodedField encodedField = appView.appInfo().resolveField(fieldInstruction.getField()); - if (encodedField != null && encodedField.isProgramField(appView)) { - if (fieldAssignmentTracker != null) { - fieldAssignmentTracker.recordFieldAccess(fieldInstruction, encodedField, code.method()); - } - if (fieldBitAccessAnalysis != null) { - fieldBitAccessAnalysis.recordFieldAccess(fieldInstruction, encodedField, feedback); + FieldResolutionResult resolutionResult = + appView.appInfo().resolveField(fieldInstruction.getField()); + if (resolutionResult.isSuccessfulResolution()) { + ProgramField field = + resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + if (field != null) { + if (fieldAssignmentTracker != null) { + fieldAssignmentTracker.recordFieldAccess( + fieldInstruction, field.getDefinition(), code.context()); + } + if (fieldBitAccessAnalysis != null) { + fieldBitAccessAnalysis.recordFieldAccess( + fieldInstruction, field.getDefinition(), feedback); + } } } } else if (instruction.isNewInstance()) { @@ -85,7 +94,7 @@ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(newInstance.clazz)); if (clazz != null) { if (fieldAssignmentTracker != null) { - fieldAssignmentTracker.recordAllocationSite(newInstance, clazz, code.method()); + fieldAssignmentTracker.recordAllocationSite(newInstance, clazz, code.context()); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java index 5e29668..fbb6443 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -119,13 +119,13 @@ } void recordFieldAccess( - FieldInstruction instruction, DexEncodedField field, DexEncodedMethod context) { + FieldInstruction instruction, DexEncodedField field, ProgramMethod context) { if (instruction.isFieldPut()) { recordFieldPut(field, instruction.value(), context); } } - private void recordFieldPut(DexEncodedField field, Value value, DexEncodedMethod context) { + private void recordFieldPut(DexEncodedField field, Value value, ProgramMethod context) { assert verifyValueIsConsistentWithFieldOptimizationInfo( value, field.getOptimizationInfo(), context); if (!value.isZero()) { @@ -133,8 +133,7 @@ } } - void recordAllocationSite( - NewInstance instruction, DexProgramClass clazz, DexEncodedMethod context) { + void recordAllocationSite(NewInstance instruction, DexProgramClass clazz, ProgramMethod context) { Map<DexEncodedField, AbstractValue> abstractInstanceFieldValuesForClass = abstractInstanceFieldValues.get(clazz); if (abstractInstanceFieldValuesForClass == null) { @@ -149,7 +148,7 @@ return; } - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context.holder()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context); if (singleTarget == null) { // We just lost track. abstractInstanceFieldValues.remove(clazz); @@ -174,7 +173,7 @@ initializationInfo.asArgumentInitializationInfo(); Value argument = invoke.arguments().get(argumentInitializationInfo.getArgumentIndex()); AbstractValue abstractValue = - entry.getValue().join(argument.getAbstractValue(appView, context.holder())); + entry.getValue().join(argument.getAbstractValue(appView, context)); assert !abstractValue.isBottom(); if (!abstractValue.isUnknown()) { entry.setValue(abstractValue); @@ -290,12 +289,12 @@ } private boolean verifyValueIsConsistentWithFieldOptimizationInfo( - Value value, FieldOptimizationInfo optimizationInfo, DexEncodedMethod context) { + Value value, FieldOptimizationInfo optimizationInfo, ProgramMethod context) { AbstractValue abstractValue = optimizationInfo.getAbstractValue(); if (abstractValue.isUnknown()) { return true; } - assert abstractValue == value.getAbstractValue(appView, context.holder()); + assert abstractValue == value.getAbstractValue(appView, context); return true; } @@ -315,7 +314,8 @@ fieldAccessInfoCollection.flattenAccessContexts(); fieldAccessInfoCollection.forEach( info -> { - DexEncodedField field = appView.appInfo().resolveField(info.getField()); + DexEncodedField field = + appView.appInfo().resolveField(info.getField()).getResolvedField(); if (field == null) { assert false; return; @@ -323,7 +323,9 @@ if (!info.hasReflectiveAccess() && !info.isWrittenFromMethodHandle()) { info.forEachWriteContext( context -> - fieldWrites.computeIfAbsent(context, ignore -> new ArrayList<>()).add(field)); + fieldWrites + .computeIfAbsent(context.getDefinition(), ignore -> new ArrayList<>()) + .add(field)); pendingFieldWrites.put(field, info.getNumberOfWriteContexts()); } });
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java index 1a6a707..b5bf1c4 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -162,7 +162,7 @@ } private boolean registerFieldAccess(DexField field, boolean isStatic) { - DexEncodedField encodedField = appView.appInfo().resolveField(field); + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField != null) { if (encodedField.isStatic() == isStatic) { if (fieldsOfInterest.contains(encodedField)) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java index 08989c0..e4bf2a9 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -6,10 +6,8 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedField; -import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexField; -import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.BasicBlock; import com.android.tools.r8.ir.code.DominatorTree; import com.android.tools.r8.ir.code.DominatorTree.Assumption; @@ -32,10 +30,9 @@ public abstract class FieldValueAnalysis { final AppView<AppInfoWithLiveness> appView; - final DexProgramClass clazz; final IRCode code; + final ProgramMethod context; final OptimizationFeedback feedback; - final DexEncodedMethod method; private DominatorTree dominatorTree; private Map<BasicBlock, AbstractFieldSet> fieldsMaybeReadBeforeBlockInclusiveCache; @@ -43,18 +40,11 @@ final Map<DexEncodedField, LinkedList<FieldInstruction>> putsPerField = new IdentityHashMap<>(); FieldValueAnalysis( - AppView<AppInfoWithLiveness> appView, - IRCode code, - OptimizationFeedback feedback, - DexProgramClass clazz, - DexEncodedMethod method) { - assert clazz != null; - assert clazz.type == method.holder(); + AppView<AppInfoWithLiveness> appView, IRCode code, OptimizationFeedback feedback) { this.appView = appView; - this.clazz = clazz; this.code = code; this.feedback = feedback; - this.method = method; + this.context = code.context(); } DominatorTree getOrCreateDominatorTree() { @@ -88,7 +78,7 @@ if (instruction.isFieldPut()) { FieldInstruction fieldPut = instruction.asFieldInstruction(); DexField field = fieldPut.getField(); - DexEncodedField encodedField = appInfo.resolveField(field); + DexEncodedField encodedField = appInfo.resolveField(field).getResolvedField(); if (encodedField != null && isSubjectToOptimization(encodedField)) { putsPerField.computeIfAbsent(encodedField, ignore -> new LinkedList<>()).add(fieldPut); } @@ -129,7 +119,6 @@ // Then check if any of the instructions that precede the given instruction in the current block // may read the field. - DexType context = method.holder(); InstructionIterator instructionIterator = block.iterator(); while (instructionIterator.hasNext()) { Instruction current = instructionIterator.next(); @@ -164,7 +153,6 @@ * and its transitive predecessors. */ private Map<BasicBlock, AbstractFieldSet> createFieldsMaybeReadBeforeBlockInclusive() { - DexType context = method.holder(); Map<BasicBlock, AbstractFieldSet> result = new IdentityHashMap<>(); Deque<BasicBlock> worklist = DequeUtils.newArrayDeque(code.entryBlock()); while (!worklist.isEmpty()) { @@ -249,7 +237,7 @@ } private boolean verifyFieldSetContainsAllFieldReadsInBlock( - KnownFieldSet readSet, BasicBlock block, DexType context) { + KnownFieldSet readSet, BasicBlock block, ProgramMethod context) { for (Instruction instruction : block.getInstructions()) { AbstractFieldSet instructionReadSet = instruction.readSet(appView, context); assert !instructionReadSet.isTop();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java index 58b4194..b818cc2 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
@@ -10,7 +10,6 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -48,11 +47,9 @@ AppView<AppInfoWithLiveness> appView, IRCode code, OptimizationFeedback feedback, - DexProgramClass clazz, - DexEncodedMethod method, DexEncodedMethod parentConstructor, InvokeDirect parentConstructorCall) { - super(appView, code, feedback, clazz, method); + super(appView, code, feedback); this.factory = appView.instanceFieldInitializationInfoFactory(); this.parentConstructor = parentConstructor; this.parentConstructorCall = parentConstructorCall; @@ -67,11 +64,10 @@ IRCode code, ClassInitializerDefaultsResult classInitializerDefaultsResult, OptimizationFeedback feedback, - DexEncodedMethod method, Timing timing) { timing.begin("Analyze instance initializer"); InstanceFieldInitializationInfoCollection result = - run(appView, code, classInitializerDefaultsResult, feedback, method); + run(appView, code, classInitializerDefaultsResult, feedback); timing.end(); return result; } @@ -80,16 +76,10 @@ AppView<?> appView, IRCode code, ClassInitializerDefaultsResult classInitializerDefaultsResult, - OptimizationFeedback feedback, - DexEncodedMethod method) { + OptimizationFeedback feedback) { assert appView.appInfo().hasLiveness(); assert appView.enableWholeProgramOptimizations(); - assert method.isInstanceInitializer(); - - DexProgramClass clazz = appView.definitionFor(method.holder()).asProgramClass(); - if (!appView.options().enableValuePropagationForInstanceFields) { - return EmptyInstanceFieldInitializationInfoCollection.getInstance(); - } + assert code.context().getDefinition().isInstanceInitializer(); InvokeDirect parentConstructorCall = IRCodeUtils.getUniqueConstructorInvoke(code.getThis(), appView.dexItemFactory()); @@ -98,7 +88,7 @@ } DexEncodedMethod parentConstructor = - parentConstructorCall.lookupSingleTarget(appView, clazz.type); + parentConstructorCall.lookupSingleTarget(appView, code.context()); if (parentConstructor == null) { return EmptyInstanceFieldInitializationInfoCollection.getInstance(); } @@ -108,8 +98,6 @@ appView.withLiveness(), code, feedback, - clazz, - method, parentConstructor, parentConstructorCall); analysis.computeFieldOptimizationInfo(classInitializerDefaultsResult); @@ -119,7 +107,7 @@ @Override boolean isSubjectToOptimization(DexEncodedField field) { - return !field.isStatic() && field.holder() == clazz.type; + return !field.isStatic() && field.holder() == context.getHolderType(); } @Override @@ -160,7 +148,7 @@ return; } - AbstractValue abstractValue = value.getAbstractValue(appView, clazz.type); + AbstractValue abstractValue = value.getAbstractValue(appView, context); if (abstractValue.isSingleValue()) { builder.recordInitializationInfo(field, abstractValue.asSingleValue()); return; @@ -185,12 +173,12 @@ return true; } - if (appView.appInfo().isFieldOnlyWrittenInMethod(field, method)) { + if (appView.appInfo().isFieldOnlyWrittenInMethod(field, context.getDefinition())) { return true; } if (appView.appInfo().isInstanceFieldWrittenOnlyInInstanceInitializers(field)) { - if (parentConstructorCall.getInvokedMethod().holder != clazz.type) { + if (parentConstructorCall.getInvokedMethod().holder != context.getHolderType()) { // The field is only written in instance initializers of the enclosing class, and the // constructor call targets a constructor in the super class. return true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java index f488267..81df82a 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -13,7 +13,6 @@ 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.DexProgramClass; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -38,12 +37,8 @@ public class StaticFieldValueAnalysis extends FieldValueAnalysis { private StaticFieldValueAnalysis( - AppView<AppInfoWithLiveness> appView, - IRCode code, - OptimizationFeedback feedback, - DexProgramClass clazz, - DexEncodedMethod method) { - super(appView, code, feedback, clazz, method); + AppView<AppInfoWithLiveness> appView, IRCode code, OptimizationFeedback feedback) { + super(appView, code, feedback); } public static void run( @@ -51,14 +46,12 @@ IRCode code, ClassInitializerDefaultsResult classInitializerDefaultsResult, OptimizationFeedback feedback, - DexEncodedMethod method, Timing timing) { assert appView.appInfo().hasLiveness(); assert appView.enableWholeProgramOptimizations(); - assert method.isClassInitializer(); + assert code.context().getDefinition().isClassInitializer(); timing.begin("Analyze class initializer"); - DexProgramClass clazz = appView.definitionFor(method.holder()).asProgramClass(); - new StaticFieldValueAnalysis(appView.withLiveness(), code, feedback, clazz, method) + new StaticFieldValueAnalysis(appView.withLiveness(), code, feedback) .computeFieldOptimizationInfo(classInitializerDefaultsResult); timing.end(); } @@ -70,7 +63,7 @@ classInitializerDefaultsResult.forEachOptimizedField( (field, value) -> { if (putsPerField.containsKey(field) - || !appView.appInfo().isFieldOnlyWrittenInMethod(field, method)) { + || !appView.appInfo().isFieldOnlyWrittenInMethod(field, context.getDefinition())) { return; } @@ -96,15 +89,15 @@ @Override boolean isSubjectToOptimization(DexEncodedField field) { return field.isStatic() - && field.holder() == clazz.type - && appView.appInfo().isFieldOnlyWrittenInMethod(field, method); + && field.holder() == context.getHolderType() + && appView.appInfo().isFieldOnlyWrittenInMethod(field, context.getDefinition()); } @Override void updateFieldOptimizationInfo(DexEncodedField field, FieldInstruction fieldPut, Value value) { // Abstract value. Value root = value.getAliasedValue(); - AbstractValue abstractValue = root.getAbstractValue(appView, clazz.type); + AbstractValue abstractValue = root.getAbstractValue(appView, context); if (abstractValue.isUnknown()) { feedback.recordFieldHasAbstractValue(field, appView, computeSingleFieldValue(field, root)); } else { @@ -149,12 +142,13 @@ */ private SingleFieldValue computeSingleEnumFieldValue(Value value) { assert !value.hasAliasedValue(); - if (!clazz.isEnum() || !value.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) { + if (!context.getHolder().isEnum() + || !value.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) { return null; } NewInstance newInstance = value.definition.asNewInstance(); - if (newInstance.clazz != clazz.type) { + if (newInstance.clazz != context.getHolderType()) { return null; } @@ -183,7 +177,8 @@ break; case STATIC_PUT: - DexEncodedField field = clazz.lookupStaticField(user.asStaticPut().getField()); + DexEncodedField field = + context.getHolder().lookupStaticField(user.asStaticPut().getField()); if (field != null && field.accessFlags.isEnum()) { if (enumField != null) { return null; @@ -219,7 +214,7 @@ return ObjectState.empty(); } - DexEncodedMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, clazz.type); + DexEncodedMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context); if (singleTarget == null) { return ObjectState.empty(); } @@ -242,7 +237,7 @@ initializationInfo.asArgumentInitializationInfo(); Value argument = uniqueConstructorInvoke.getArgument(argumentInitializationInfo.getArgumentIndex()); - builder.recordFieldHasValue(field, argument.getAbstractValue(appView, clazz.type)); + builder.recordFieldHasValue(field, argument.getAbstractValue(appView, context)); } else if (initializationInfo.isSingleValue()) { builder.recordFieldHasValue(field, initializationInfo.asSingleValue()); } @@ -251,12 +246,12 @@ } private boolean isEnumValuesArray(Value value) { - assert clazz.isEnum(); + assert context.getHolder().isEnum(); DexItemFactory dexItemFactory = appView.dexItemFactory(); DexField valuesField = dexItemFactory.createField( - clazz.type, - clazz.type.toArrayType(1, dexItemFactory), + context.getHolderType(), + context.getHolderType().toArrayType(1, dexItemFactory), dexItemFactory.enumValuesFieldName); Value root = value.getAliasedValue();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java index 4879783..400b509 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -6,7 +6,6 @@ import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexField; @@ -14,6 +13,8 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.FieldAccessInfo; import com.android.tools.r8.graph.FieldAccessInfoCollection; +import com.android.tools.r8.graph.FieldResolutionResult; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.IRCodeUtils; @@ -178,42 +179,39 @@ }); } - public boolean isDeadProtoExtensionField(DexField field) { + public boolean isDeadProtoExtensionField(DexField fieldReference) { AppInfoWithLiveness appInfo = appView.appInfo(); - DexEncodedField encodedField = appInfo.resolveField(field); - if (encodedField != null) { - return isDeadProtoExtensionField( - encodedField, appInfo.getFieldAccessInfoCollection(), appInfo.getPinnedItems()); + FieldResolutionResult resolutionResult = appInfo.resolveField(fieldReference); + if (resolutionResult.isSuccessfulResolution()) { + ProgramField field = + resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + return field != null + && isDeadProtoExtensionField( + field, appInfo.getFieldAccessInfoCollection(), appInfo.getPinnedItems()); } return false; } public boolean isDeadProtoExtensionField( - DexEncodedField encodedField, + ProgramField field, FieldAccessInfoCollection<?> fieldAccessInfoCollection, Set<DexReference> pinnedItems) { - DexField field = encodedField.field; - if (pinnedItems.contains(field)) { + if (pinnedItems.contains(field.getReference())) { return false; } - if (field.type != references.generatedExtensionType) { + if (field.getReference().type != references.generatedExtensionType) { return false; } - DexClass clazz = appView.definitionFor(encodedField.holder()); - if (clazz == null || !clazz.isProgramClass()) { - return false; - } - - FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(encodedField.field); + FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.getReference()); if (fieldAccessInfo == null) { return false; } - DexEncodedMethod uniqueReadContext = fieldAccessInfo.getUniqueReadContext(); + ProgramMethod uniqueReadContext = fieldAccessInfo.getUniqueReadContext(); return uniqueReadContext != null - && references.isFindLiteExtensionByNumberMethod(uniqueReadContext.method); + && references.isFindLiteExtensionByNumberMethod(uniqueReadContext); } private void forEachDeadProtoExtensionField(Consumer<DexField> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java index c2c9a50..861c0cd 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -140,6 +140,10 @@ && method.holder != extensionRegistryLiteType; } + public boolean isFindLiteExtensionByNumberMethod(ProgramMethod method) { + return isFindLiteExtensionByNumberMethod(method.getReference()); + } + public boolean isGeneratedMessageLiteBuilder(DexProgramClass clazz) { return (clazz.superType == generatedMessageLiteBuilderType || clazz.superType == generatedMessageLiteExtendableBuilderType)
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java index 8001121..d1bf3d1 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -8,12 +8,15 @@ import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.FieldResolutionResult; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.analysis.EnqueuerAnalysis; import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteShrinker; @@ -56,7 +59,7 @@ // keep fields that could reach extensions to be conservative. public class ProtoEnqueuerExtension extends EnqueuerAnalysis { - private final AppView<?> appView; + private final AppView<? extends AppInfoWithClassHierarchy> appView; private final RawMessageInfoDecoder decoder; private final ProtoFieldTypeFactory factory; private final ProtoReferences references; @@ -85,7 +88,7 @@ // Mapping from extension container types to the extensions for that type. private final Map<DexType, Set<DexType>> extensionGraph = new IdentityHashMap<>(); - public ProtoEnqueuerExtension(AppView<?> appView) { + public ProtoEnqueuerExtension(AppView<? extends AppInfoWithClassHierarchy> appView) { ProtoShrinker protoShrinker = appView.protoShrinker(); this.appView = appView; this.decoder = protoShrinker.decoder; @@ -94,7 +97,8 @@ } @Override - public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) { + public void processNewlyLiveClass( + DexProgramClass clazz, EnqueuerWorklist worklist, DexDefinitionSupplier definitionSupplier) { assert appView.appInfo().hasClassHierarchy(); AppInfoWithClassHierarchy appInfo = appView.appInfo().withClassHierarchy(); if (appInfo.isStrictSubtypeOf(clazz.type, references.generatedMessageLiteType)) { @@ -258,7 +262,8 @@ Instruction definition = returnValue.definition; if (definition.isStaticGet()) { StaticGet staticGet = definition.asStaticGet(); - DexEncodedField field = appView.appInfo().resolveField(staticGet.getField()); + DexEncodedField field = + appView.appInfo().resolveField(staticGet.getField()).getResolvedField(); if (field == null) { assert false; continue; @@ -355,7 +360,7 @@ ProgramMethod dynamicMethod = protoMessageInfo.getDynamicMethod(); for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.getFields()) { - DexEncodedField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo); + ProgramField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo); if (valueStorage == null) { continue; } @@ -369,21 +374,21 @@ // (i) optimize field reads into loading the default value of the field or (ii) remove // field writes to proto fields that could be read using reflection by the proto // library. - enqueuer.registerReflectiveFieldAccess(valueStorage.field, dynamicMethod); + enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod); } valueStorageIsLive = true; } else if (reachesMapOrRequiredField(protoFieldInfo)) { // Map/required fields cannot be removed. Therefore, we mark such fields as both read and // written such that we cannot optimize any field reads or writes. - enqueuer.registerReflectiveFieldAccess(valueStorage.field, dynamicMethod); + enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod); worklist.enqueueMarkReachableFieldAction( - dynamicMethod.getHolder(), valueStorage, KeepReason.reflectiveUseIn(dynamicMethod)); + valueStorage, KeepReason.reflectiveUseIn(dynamicMethod)); valueStorageIsLive = true; } else { valueStorageIsLive = false; } - DexEncodedField newlyLiveField = null; + ProgramField newlyLiveField = null; if (valueStorageIsLive) { // For one-of fields, mark the corresponding one-of-case field as live, and for proto2 // singular fields, mark the corresponding hazzer-bit field as live. @@ -391,27 +396,28 @@ newlyLiveField = protoFieldInfo.getOneOfCaseField(appView, protoMessageInfo); } else if (protoFieldInfo.hasHazzerBitField(protoMessageInfo)) { newlyLiveField = protoFieldInfo.getHazzerBitField(appView, protoMessageInfo); - enqueuer.registerReflectiveFieldAccess(valueStorage.field, dynamicMethod); + enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod); } } else { // For one-of fields, mark the one-of field as live if the one-of-case field is live, and // for proto2 singular fields, mark the field as live if the corresponding hazzer-bit // field is live. if (protoFieldInfo.getType().isOneOf()) { - DexEncodedField oneOfCaseField = + ProgramField oneOfCaseField = protoFieldInfo.getOneOfCaseField(appView, protoMessageInfo); if (oneOfCaseField != null && enqueuer.isFieldLive(oneOfCaseField)) { newlyLiveField = valueStorage; } } else if (protoFieldInfo.hasHazzerBitField(protoMessageInfo)) { - DexEncodedField hazzerBitField = + ProgramField hazzerBitField = protoFieldInfo.getHazzerBitField(appView, protoMessageInfo); if (hazzerBitField == null || !enqueuer.isFieldLive(hazzerBitField)) { continue; } if (appView.options().enableFieldBitAccessAnalysis && appView.isAllCodeProcessed()) { - FieldOptimizationInfo optimizationInfo = hazzerBitField.getOptimizationInfo(); + FieldOptimizationInfo optimizationInfo = + hazzerBitField.getDefinition().getOptimizationInfo(); int hazzerBitIndex = protoFieldInfo.getHazzerBitFieldIndex(protoMessageInfo); if (!BitUtils.isBitSet(optimizationInfo.getReadBits(), hazzerBitIndex)) { continue; @@ -428,20 +434,19 @@ ProgramMethod defaultInitializer = dynamicMethod.getHolder().getProgramDefaultInitializer(); assert defaultInitializer != null; - Predicate<DexEncodedMethod> neitherDefaultConstructorNorDynamicMethod = + Predicate<ProgramMethod> neitherDefaultConstructorNorDynamicMethod = writer -> - writer != defaultInitializer.getDefinition() - && writer != dynamicMethod.getDefinition(); + !writer.isStructurallyEqualTo(defaultInitializer) + && !writer.isStructurallyEqualTo(dynamicMethod); if (enqueuer.isFieldWrittenInMethodSatisfying( newlyLiveField, neitherDefaultConstructorNorDynamicMethod)) { - enqueuer.registerReflectiveFieldRead(newlyLiveField.field, dynamicMethod); + enqueuer.registerReflectiveFieldRead(newlyLiveField.getReference(), dynamicMethod); } // Unconditionally register the hazzer and one-of proto fields as written from // dynamicMethod(). - if (enqueuer.registerReflectiveFieldWrite(newlyLiveField.field, dynamicMethod)) { + if (enqueuer.registerReflectiveFieldWrite(newlyLiveField.getReference(), dynamicMethod)) { worklist.enqueueMarkReachableFieldAction( - dynamicMethod.getHolder(), newlyLiveField, KeepReason.reflectiveUseIn(dynamicMethod)); } @@ -474,7 +479,7 @@ // NOTE: If `valueStorage` is not a live field, then code for it will not be emitted in the // schema, and therefore we do need to trace the const-class instructions that will be // emitted for it. - DexEncodedField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo); + ProgramField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo); if (valueStorage != null && enqueuer.isFieldLive(valueStorage)) { for (ProtoObject object : objects) { if (object.isProtoObjectFromStaticGet()) { @@ -511,27 +516,32 @@ return; } - DexField oneOfCaseField = oneOfCaseObject.asLiveProtoFieldObject().getField(); - DexEncodedField encodedOneOfCaseField = appView.appInfo().resolveField(oneOfCaseField); - if (encodedOneOfCaseField == null) { + DexField oneOfCaseFieldReference = oneOfCaseObject.asLiveProtoFieldObject().getField(); + FieldResolutionResult oneOfCaseFieldResolutionResult = + appView.appInfo().resolveField(oneOfCaseFieldReference); + if (oneOfCaseFieldResolutionResult.isFailedOrUnknownResolution()) { assert false; return; } - DexProgramClass clazz = - asProgramClassOrNull(appView.definitionFor(encodedOneOfCaseField.holder())); - if (clazz == null) { + ProgramField oneOfCaseField = + oneOfCaseFieldResolutionResult + .asSuccessfulResolution() + .getResolutionPair() + .asProgramField(); + if (oneOfCaseField == null) { assert false; return; } - ProgramMethod dynamicMethod = clazz.lookupProgramMethod(references.dynamicMethod); + ProgramMethod dynamicMethod = + oneOfCaseField.getHolder().lookupProgramMethod(references.dynamicMethod); if (dynamicMethod == null) { assert false; return; } - if (!enqueuer.isFieldLive(encodedOneOfCaseField)) { + if (!enqueuer.isFieldLive(oneOfCaseField)) { return; } @@ -541,21 +551,24 @@ return; } - DexField oneOfField = oneOfObject.asLiveProtoFieldObject().getField(); - DexEncodedField encodedOneOfField = appView.appInfo().resolveField(oneOfField); - if (encodedOneOfField == null) { + DexField oneOfFieldReference = oneOfObject.asLiveProtoFieldObject().getField(); + FieldResolutionResult oneOfFieldResolutionResult = + appView.appInfo().resolveField(oneOfFieldReference); + if (oneOfFieldResolutionResult.isFailedOrUnknownResolution()) { assert false; return; } - if (encodedOneOfField.holder() != encodedOneOfCaseField.holder()) { + ProgramField oneOfField = + oneOfFieldResolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + if (oneOfField == null || oneOfField.getHolder() != oneOfCaseField.getHolder()) { assert false; return; } - if (enqueuer.registerReflectiveFieldWrite(encodedOneOfField.field, dynamicMethod)) { + if (enqueuer.registerReflectiveFieldWrite(oneOfField.getReference(), dynamicMethod)) { worklist.enqueueMarkReachableFieldAction( - clazz.asProgramClass(), encodedOneOfField, KeepReason.reflectiveUseIn(dynamicMethod)); + oneOfField, KeepReason.reflectiveUseIn(dynamicMethod)); } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java index 944d069..6704f91 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
@@ -6,9 +6,11 @@ import static com.android.tools.r8.ir.analysis.proto.schema.ProtoMessageInfo.BITS_PER_HAS_BITS_WORD; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.FieldResolutionResult; +import com.android.tools.r8.graph.ProgramField; import java.util.List; import java.util.OptionalInt; @@ -120,7 +122,8 @@ return protoMessageInfo.isProto2() && type.isSingular(); } - public DexEncodedField getHazzerBitField(AppView<?> appView, ProtoMessageInfo protoMessageInfo) { + public ProgramField getHazzerBitField( + AppView<? extends AppInfoWithClassHierarchy> appView, ProtoMessageInfo protoMessageInfo) { assert hasHazzerBitField(protoMessageInfo); int hasBitsIndex = getAuxData() / BITS_PER_HAS_BITS_WORD; @@ -128,7 +131,12 @@ ProtoObject object = protoMessageInfo.getHasBitsObjects().get(hasBitsIndex); assert object.isLiveProtoFieldObject(); - return appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField()); + FieldResolutionResult resolutionResult = + appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField()); + if (resolutionResult.isSuccessfulResolution()) { + return resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + } + return null; } public int getHazzerBitFieldIndex(ProtoMessageInfo protoMessageInfo) { @@ -162,12 +170,17 @@ * } * </pre> */ - public DexEncodedField getOneOfCaseField(AppView<?> appView, ProtoMessageInfo protoMessageInfo) { + public ProgramField getOneOfCaseField( + AppView<? extends AppInfoWithClassHierarchy> appView, ProtoMessageInfo protoMessageInfo) { assert type.isOneOf(); - ProtoObject object = protoMessageInfo.getOneOfObjects().get(getAuxData()).getOneOfCaseObject(); assert object.isLiveProtoFieldObject(); - return appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField()); + FieldResolutionResult resolutionResult = + appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField()); + if (resolutionResult.isSuccessfulResolution()) { + return resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + } + return null; } /** @@ -176,13 +189,19 @@ * <p>Java field into which the value is stored; constituents of a oneof all share the same * storage. */ - public DexEncodedField getValueStorage(AppView<?> appView, ProtoMessageInfo protoMessageInfo) { + public ProgramField getValueStorage( + AppView<? extends AppInfoWithClassHierarchy> appView, ProtoMessageInfo protoMessageInfo) { ProtoObject object = type.isOneOf() ? protoMessageInfo.getOneOfObjects().get(getAuxData()).getOneOfObject() : objects.get(0); assert object.isLiveProtoFieldObject(); - return appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField()); + FieldResolutionResult resolutionResult = + appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField()); + if (resolutionResult.isSuccessfulResolution()) { + return resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + } + return null; } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/sideeffect/ClassInitializerSideEffectAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/sideeffect/ClassInitializerSideEffectAnalysis.java index b3aaf9c..f92edd0 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/sideeffect/ClassInitializerSideEffectAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/sideeffect/ClassInitializerSideEffectAnalysis.java
@@ -6,7 +6,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedField; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ValueMayDependOnEnvironmentAnalysis; import com.android.tools.r8.ir.code.ArrayPut; import com.android.tools.r8.ir.code.IRCode; @@ -15,6 +15,7 @@ import com.android.tools.r8.ir.code.NewArrayFilledData; import com.android.tools.r8.ir.code.StaticPut; import com.android.tools.r8.ir.code.Value; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.OptionalBool; public class ClassInitializerSideEffectAnalysis { @@ -38,8 +39,8 @@ * non-static-put instructions may have side effects. */ public static ClassInitializerSideEffect classInitializerCanBePostponed( - AppView<?> appView, IRCode code) { - DexType context = code.method().holder(); + AppView<AppInfoWithLiveness> appView, IRCode code) { + ProgramMethod context = code.context(); OptionalBool controlFlowMayDependOnEnvironment = OptionalBool.unknown(); boolean mayHaveSideEffects = false; @@ -111,9 +112,10 @@ if (instruction.isStaticPut()) { StaticPut staticPut = instruction.asStaticPut(); - DexEncodedField field = appView.appInfo().resolveField(staticPut.getField()); + DexEncodedField field = + appView.appInfo().resolveField(staticPut.getField()).getResolvedField(); if (field == null - || field.holder() != context + || field.holder() != context.getHolderType() || environmentAnalysis.valueMayDependOnEnvironment(staticPut.value()) || instruction.instructionInstanceCanThrow(appView, context).isThrowing()) { return ClassInitializerSideEffect.SIDE_EFFECTS_THAT_CANNOT_BE_POSTPONED;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java index 76213c6..bcb5c0b 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -75,7 +75,7 @@ Value returnedValue = code.createValue(classClassType(appView, definitelyNotNull()), debugLocalInfo); ConstClass instruction = new ConstClass(returnedValue, type); - assert !instruction.instructionMayHaveSideEffects(appView, code.method().holder()); + assert !instruction.instructionMayHaveSideEffects(appView, code.context()); return instruction; } @@ -96,7 +96,7 @@ } @Override - public boolean isMaterializableInAllContexts(AppView<?> appView) { + public boolean isMaterializableInAllContexts(AppView<AppInfoWithLiveness> appView) { DexType baseType = type.toBaseType(appView.dexItemFactory()); if (baseType.isClassType()) { DexClass clazz = appView.definitionFor(type);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java index 7bccd30..14dee6f 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -81,7 +81,7 @@ public boolean isMaterializableInContext( AppView<AppInfoWithLiveness> appView, ProgramMethod context) { return AccessControl.isFieldAccessible( - appView.appInfo().resolveField(field), + appView.appInfo().resolveField(field).getResolvedField(), appView.definitionForHolder(field), context.getHolder(), appView.appInfo()) @@ -89,8 +89,8 @@ } @Override - public boolean isMaterializableInAllContexts(AppView<?> appView) { - DexEncodedField encodedField = appView.appInfo().resolveField(field); + public boolean isMaterializableInAllContexts(AppView<AppInfoWithLiveness> appView) { + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField == null) { assert false; return false;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java index 67a0858..e6b1ee6 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -86,7 +86,7 @@ } @Override - public boolean isMaterializableInAllContexts(AppView<?> appView) { + public boolean isMaterializableInAllContexts(AppView<AppInfoWithLiveness> appView) { return true; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java index 457d49b..ab7c218 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -87,7 +87,7 @@ } @Override - public boolean isMaterializableInAllContexts(AppView<?> appView) { + public boolean isMaterializableInAllContexts(AppView<AppInfoWithLiveness> appView) { return true; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java index f0425b0..3ce27a0 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
@@ -43,7 +43,7 @@ public abstract boolean isMaterializableInContext( AppView<AppInfoWithLiveness> appView, ProgramMethod context); - public abstract boolean isMaterializableInAllContexts(AppView<?> appView); + public abstract boolean isMaterializableInAllContexts(AppView<AppInfoWithLiveness> appView); @Override public abstract SingleValue rewrittenWithLens(
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java index 8cd1503..3cd25ea 100644 --- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java +++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java
@@ -7,7 +7,7 @@ import com.android.tools.r8.cf.code.CfNop; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -61,7 +61,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return ConstraintWithTarget.ALWAYS; } @@ -76,7 +76,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java index 2a32bb6..4b99975 100644 --- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java +++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
@@ -6,7 +6,7 @@ import com.android.tools.r8.cf.LoadStoreHelper; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -62,7 +62,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forAlwaysMaterializingUser(); } @@ -77,7 +77,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java index 2ace686..5b68bf5 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Argument.java +++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -101,7 +102,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forArgument(); } @@ -136,7 +137,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java index 432cf11..845cb26 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java +++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -19,6 +19,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.ArrayTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -151,7 +152,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forArrayGet(); } @@ -237,7 +238,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return array() == value; } @@ -263,7 +264,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java index a1ed1d7..fcea78c 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java +++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.cf.code.CfArrayLength; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -74,7 +74,7 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { if (array().type.isNullable()) { return AbstractError.specific(appView.dexItemFactory().npeType); } @@ -84,13 +84,13 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(appView, context).isThrowing(); } @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override @@ -114,7 +114,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forArrayLength(); } @@ -140,7 +140,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return array() == value; } @@ -155,7 +155,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java index 37daada..860473c 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java +++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -15,7 +15,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.ArrayTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -134,7 +134,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { // In debug mode, ArrayPut has a side-effect on the locals. if (appView.options().debug) { return true; @@ -192,7 +192,7 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override @@ -220,7 +220,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forArrayPut(); } @@ -240,7 +240,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return array() == value; } @@ -260,7 +260,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Assume.java b/src/main/java/com/android/tools/r8/ir/code/Assume.java index e5316e4..c6012bd 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Assume.java +++ b/src/main/java/com/android/tools/r8/ir/code/Assume.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.code.Assume.Assumption; @@ -238,7 +239,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forAssume(); } @@ -270,7 +271,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java index f0d4eff..613ff5b 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Binop.java +++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.cf.LoadStoreHelper; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -123,7 +123,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forBinop(); } @@ -144,7 +144,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java index da952bd..cdbf6f0 100644 --- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java +++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -16,6 +16,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -96,12 +97,12 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(appView, context).isThrowing(); } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { if (appView.options().debug || !appView.appInfo().hasLiveness()) { return AbstractError.top(); } @@ -154,8 +155,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forCheckCast(type, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forCheckCast(type, context.getHolder()); } @Override @@ -225,7 +226,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java index c2d5232..759e764 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -22,6 +23,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import com.android.tools.r8.shaking.AppInfoWithLiveness; public class ConstClass extends ConstInstruction { @@ -99,7 +101,7 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { DexType baseType = getValue().toBaseType(appView.dexItemFactory()); if (baseType.isPrimitiveType()) { return AbstractError.bottom(); @@ -108,7 +110,7 @@ // Not applicable for D8. if (!appView.enableWholeProgramOptimizations()) { // Unless the type of interest is same as the context. - if (baseType == context) { + if (baseType == context.getHolderType()) { return AbstractError.bottom(); } return AbstractError.top(); @@ -133,13 +135,13 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(appView, context).isThrowing(); } @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override @@ -164,8 +166,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forConstClass(clazz, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forConstClass(clazz, context.getHolder()); } @Override @@ -189,7 +191,8 @@ } @Override - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { if (!instructionMayHaveSideEffects(appView, context)) { return appView.abstractValueFactory().createSingleConstClassValue(clazz); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java b/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java index 8db125c..0e8ce5d 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; @@ -50,7 +50,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forConstInstruction(); } @@ -60,7 +60,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java index a390b3f..3973d6e 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -78,7 +79,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forConstMethodHandle(); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java index 774475d..6f153a6 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -124,7 +125,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forConstMethodType(); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java index fcb0c1b..dc66e3c 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.constant.Bottom; import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement; import com.android.tools.r8.ir.analysis.constant.LatticeElement; @@ -25,6 +26,7 @@ import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.InternalOutputMode; import com.android.tools.r8.utils.NumberUtils; import java.util.Set; @@ -333,7 +335,8 @@ } @Override - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { return appView.abstractValueFactory().createSingleNumberValue(value); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java index a90a67e..3bd1d56 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; @@ -17,6 +18,7 @@ import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import java.io.UTFDataFormatException; public class ConstString extends ConstInstruction { @@ -156,12 +158,13 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } @Override - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { if (!instructionInstanceCanThrow()) { return appView.abstractValueFactory().createSingleStringValue(value); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java index 64e2c14..292d6b7 100644 --- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java +++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
@@ -6,7 +6,7 @@ import com.android.tools.r8.cf.LoadStoreHelper; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -66,7 +66,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forDebugLocalRead(); } @@ -88,7 +88,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java index 5b4c66b..842eaa4 100644 --- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java +++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
@@ -7,7 +7,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DebugLocalInfo; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -99,7 +99,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forDebugLocalsChange(); } @@ -135,7 +135,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java index b9ab9cd..fd6f9a9 100644 --- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java +++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -7,7 +7,7 @@ import com.android.tools.r8.cf.code.CfNop; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -62,7 +62,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forDebugPosition(); } @@ -89,7 +89,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java index bc29749..959dbfc 100644 --- a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java +++ b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo; @@ -157,12 +158,12 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forDexItemBasedConstString(item, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forDexItemBasedConstString(item, context.getHolder()); } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup.java b/src/main/java/com/android/tools/r8/ir/code/Dup.java index cddc41e..070b8e9 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Dup.java +++ b/src/main/java/com/android/tools/r8/ir/code/Dup.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -94,7 +94,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forDup(); } @@ -119,7 +119,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup2.java b/src/main/java/com/android/tools/r8/ir/code/Dup2.java index 465c408..7053383 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Dup2.java +++ b/src/main/java/com/android/tools/r8/ir/code/Dup2.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -108,7 +108,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forDup2(); } @@ -133,7 +133,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java index 888536f..436de09 100644 --- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -3,15 +3,14 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.code; -import static com.android.tools.r8.optimize.MemberRebindingAnalysis.isMemberVisibleFromOriginalContext; - import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; 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.DexType; +import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet; import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet; @@ -61,56 +60,32 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { return instructionInstanceCanThrow(appView, context, SideEffectAssumption.NONE); } public AbstractError instructionInstanceCanThrow( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { - DexEncodedField resolvedField; - if (appView.enableWholeProgramOptimizations()) { - // TODO(b/123857022): Should be possible to use definitionFor(). - resolvedField = appView.appInfo().resolveField(field); - } else { - // In D8, only allow the field in the same context. - if (field.holder != context) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { + SuccessfulFieldResolutionResult resolutionResult = + appView.appInfo().resolveField(field, context).asSuccessfulResolution(); + if (resolutionResult == null) { + return AbstractError.top(); + } + DexEncodedField resolvedField = resolutionResult.getResolvedField(); + // Check if the instruction may fail with an IncompatibleClassChangeError. + if (resolvedField.isStatic() != isStaticFieldInstruction()) { + return AbstractError.top(); + } + // Check if the resolution target is accessible. + if (resolutionResult.getResolvedHolder() != context.getHolder()) { + if (resolutionResult + .isAccessibleFrom(context, appView.appInfo().withClassHierarchy()) + .isPossiblyFalse()) { return AbstractError.top(); } - // Note that, in D8, we are not using AppInfo#resolveField to avoid traversing the hierarchy. - DexClass holder = appView.definitionFor(field.holder); - if (holder == null) { - return AbstractError.top(); - } - resolvedField = holder.lookupField(field); - } - // * NoSuchFieldError (resolution failure). - if (resolvedField == null) { - if (appView.enableWholeProgramOptimizations()) { - return AbstractError.specific(appView.dexItemFactory().noSuchFieldErrorType); - } else { - // In D8, the field lookup can only consult the context definition. Nothing can be concluded - // from a lookup failure. For example, it could be ICCE or IAE if the current field access - // is referring to incompatible or invisible field in a super type, respectively. - return AbstractError.top(); - } - } - // * IncompatibleClassChangeError (instance-* for static field and vice versa). - if (resolvedField.isStaticMember()) { - if (isInstanceGet() || isInstancePut()) { - return AbstractError.specific(appView.dexItemFactory().icceType); - } - } else { - if (isStaticGet() || isStaticPut()) { - return AbstractError.specific(appView.dexItemFactory().icceType); - } - } - // * IllegalAccessError (not visible from the access context). - if (!isMemberVisibleFromOriginalContext( - appView, context, field.holder, resolvedField.accessFlags)) { - return AbstractError.specific(appView.dexItemFactory().illegalAccessErrorType); } // TODO(b/137168535): Without non-null tracking, only locally created receiver is allowed in D8. - // * NullPointerException (null receiver). + // Check if the instruction may fail with a NullPointerException (null receiver). if (isInstanceGet() || isInstancePut()) { if (!assumption.canAssumeReceiverIsNotNull()) { Value receiver = inValues.get(0); @@ -138,7 +113,7 @@ if (field.holder.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet())) { return AbstractError.top(); } @@ -153,7 +128,7 @@ } @Override - public AbstractFieldSet readSet(AppView<?> appView, DexType context) { + public AbstractFieldSet readSet(AppView<AppInfoWithLiveness> appView, ProgramMethod context) { if (instructionMayTriggerMethodInvocation(appView, context)) { // This may trigger class initialization, which could potentially read any field. return UnknownFieldSet.getInstance(); @@ -163,7 +138,7 @@ DexField field = getField(); DexEncodedField encodedField = null; if (appView.enableWholeProgramOptimizations()) { - encodedField = appView.appInfo().resolveField(field); + encodedField = appView.appInfo().resolveField(field).getResolvedField(); } else { DexClass clazz = appView.definitionFor(field.holder); if (clazz != null) { @@ -219,7 +194,7 @@ DexItemFactory dexItemFactory = appView.dexItemFactory(); DexEncodedMethod resolutionResult = appInfo - .resolveMethod(clazz.type, dexItemFactory.objectMembers.finalize) + .resolveMethodOnClass(dexItemFactory.objectMembers.finalize, clazz) .getSingleTarget(); return resolutionResult != null && resolutionResult.isProgramMethod(appView); } @@ -228,9 +203,10 @@ } @Override - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { assert isFieldGet(); - DexEncodedField field = appView.appInfo().resolveField(getField()); + DexEncodedField field = appView.appInfo().resolveField(getField()).getResolvedField(); if (field != null) { return field.getOptimizationInfo().getAbstractValue(); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java index 107e06e..e06cdbee 100644 --- a/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java +++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.ir.code; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexItemFactory; @@ -44,11 +45,14 @@ * does not guarantee that the assignments found dominate all the normal exits. */ public static Map<DexEncodedField, StaticPut> findUniqueStaticPuts( - AppView<?> appView, IRCode code, Set<DexEncodedField> fields) { + AppView<? extends AppInfoWithClassHierarchy> appView, + IRCode code, + Set<DexEncodedField> fields) { Set<DexEncodedField> writtenMoreThanOnce = Sets.newIdentityHashSet(); Map<DexEncodedField, StaticPut> uniqueStaticPuts = new IdentityHashMap<>(); for (StaticPut staticPut : code.<StaticPut>instructions(Instruction::isStaticPut)) { - DexEncodedField field = appView.appInfo().resolveField(staticPut.getField()); + DexEncodedField field = + appView.appInfo().resolveField(staticPut.getField()).getResolvedField(); if (field == null || !fields.contains(field) || writtenMoreThanOnce.contains(field)) { continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InitClass.java b/src/main/java/com/android/tools/r8/ir/code/InitClass.java index 02ee0eb..3ff5c53 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InitClass.java +++ b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; @@ -21,6 +22,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.google.common.collect.Sets; public class InitClass extends Instruction { @@ -78,8 +80,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInitClass( @@ -92,14 +94,14 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { if (!isTypeVisibleFromContext(appView, context, clazz)) { return AbstractError.top(); } if (clazz.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet())) { return AbstractError.top(); } @@ -108,24 +110,24 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(appView, context).isThrowing(); } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { if (appView.enableWholeProgramOptimizations()) { // In R8, check if the class initialization of `clazz` or any of its ancestor types may have // side effects. return clazz.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet()); } else { // In D8, this instruction may trigger class initialization if `clazz` is different from the // current context. - return clazz != context; + return clazz != context.getHolderType(); } } @@ -146,8 +148,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInitClass(clazz, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInitClass(clazz, context.getHolder()); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceFieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/InstanceFieldInstruction.java index e78d3a7..9077c97 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstanceFieldInstruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstanceFieldInstruction.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.ir.code; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Instruction.SideEffectAssumption; public interface InstanceFieldInstruction { @@ -17,7 +17,7 @@ Value object(); boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption); + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption); FieldInstruction asFieldInstruction();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java index 3050da7..38c1813 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -19,6 +19,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -28,6 +29,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import java.util.Set; public class InstanceGet extends FieldInstruction implements InstanceFieldInstruction { @@ -116,7 +118,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(appView, context, assumption).isThrowing(); } @@ -127,7 +129,7 @@ // * IncompatibleClassChangeError (instance-* instruction for static fields) // * IllegalAccessError (not visible from the access context) // * NullPointerException (null receiver) - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override @@ -151,8 +153,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInstanceGet(getField(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInstanceGet(getField(), context.getHolder()); } @Override @@ -204,7 +206,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return object() == value; } @@ -221,8 +223,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInstanceGet( @@ -230,7 +232,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java index c18e3c5..3d7ae52 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -86,8 +87,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInstanceOf(type, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInstanceOf(type, context.getHolder()); } @Override @@ -117,7 +118,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java index fd76ad3..d5aad2d 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -19,6 +19,7 @@ import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -115,7 +116,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { if (appView.appInfo().hasLiveness()) { AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo(); @@ -124,7 +125,8 @@ return true; } - DexEncodedField encodedField = appInfoWithLiveness.resolveField(getField()); + DexEncodedField encodedField = + appInfoWithLiveness.resolveField(getField()).getResolvedField(); assert encodedField != null : "NoSuchFieldError (resolution failure) should be caught."; return appInfoWithLiveness.isFieldRead(encodedField) || isStoringObjectWithFinalizer(appViewWithLiveness, encodedField); @@ -142,7 +144,7 @@ // * IllegalAccessError (not visible from the access context) // * NullPointerException (null receiver) // * not read at all - boolean haveSideEffects = instructionMayHaveSideEffects(appView, code.method().holder()); + boolean haveSideEffects = instructionMayHaveSideEffects(appView, code.context()); assert appView.enableWholeProgramOptimizations() || haveSideEffects : "Expected instance-put instruction to have side effects in D8"; return !haveSideEffects; @@ -190,8 +192,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInstancePut(getField(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInstancePut(getField(), context.getHolder()); } @Override @@ -232,7 +234,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return object() == value; } @@ -249,8 +251,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInstancePut( @@ -258,7 +260,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java index b280728..5fa8d11 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DebugLocalInfo; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -30,6 +31,7 @@ import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.ir.regalloc.RegisterAllocator; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.CfgPrinter; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.StringUtils.BraceType; @@ -139,7 +141,8 @@ return oldOutValue; } - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { assert hasOutValue(); return UnknownValue.getInstance(); } @@ -532,7 +535,8 @@ return false; } - public boolean isBlockLocalInstructionWithoutSideEffects(AppView<?> appView, DexType context) { + public boolean isBlockLocalInstructionWithoutSideEffects( + AppView<?> appView, ProgramMethod context) { return definesBlockLocalValue() && !instructionMayHaveSideEffects(appView, context); } @@ -570,12 +574,12 @@ return instructionTypeCanThrow(); } - public boolean instructionMayHaveSideEffects(AppView<?> appView, DexType context) { + public boolean instructionMayHaveSideEffects(AppView<?> appView, ProgramMethod context) { return instructionMayHaveSideEffects(appView, context, SideEffectAssumption.NONE); } public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(); } @@ -584,9 +588,9 @@ * indirectly (e.g., via class initialization). */ public abstract boolean instructionMayTriggerMethodInvocation( - AppView<?> appView, DexType context); + AppView<?> appView, ProgramMethod context); - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { return instructionInstanceCanThrow() ? AbstractError.top() : AbstractError.bottom(); } @@ -601,7 +605,7 @@ * Returns an abstraction of the set of fields that may possibly be read as a result of executing * this instruction. */ - public AbstractFieldSet readSet(AppView<?> appView, DexType context) { + public AbstractFieldSet readSet(AppView<AppInfoWithLiveness> appView, ProgramMethod context) { if (instructionMayTriggerMethodInvocation(appView, context) && instructionMayHaveSideEffects(appView, context)) { return UnknownFieldSet.getInstance(); @@ -1378,7 +1382,7 @@ * <p>The type is used to judge visibility constraints and also for dispatch decisions. */ public abstract ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context); public abstract void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper); @@ -1432,7 +1436,7 @@ * @return true if the instruction throws NullPointerException if value is null at runtime, false * otherwise. */ - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return false; } @@ -1460,8 +1464,8 @@ */ public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return false;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java index c3fec64..29b8a3b 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -165,7 +166,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forInvokeCustom(); } @@ -196,7 +197,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return true; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java index e492db1..095db29 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; 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.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -121,24 +122,25 @@ } @Override - public DexEncodedMethod lookupSingleTarget(AppView<?> appView, DexType invocationContext) { + public DexEncodedMethod lookupSingleTarget( + AppView<?> appView, ProgramMethod context, Value receiver) { DexMethod invokedMethod = getInvokedMethod(); if (appView.appInfo().hasLiveness()) { AppInfoWithLiveness appInfo = appView.appInfo().withLiveness(); - DexEncodedMethod result = appInfo.lookupDirectTarget(invokedMethod, invocationContext); + DexEncodedMethod result = appInfo.lookupDirectTarget(invokedMethod, context); assert verifyD8LookupResult( - result, appView.appInfo().lookupDirectTargetOnItself(invokedMethod, invocationContext)); + result, appView.appInfo().lookupDirectTargetOnItself(invokedMethod, context)); return result; } // In D8, we can treat invoke-direct instructions as having a single target if the invoke is // targeting a method in the enclosing class. - return appView.appInfo().lookupDirectTargetOnItself(invokedMethod, invocationContext); + return appView.appInfo().lookupDirectTargetOnItself(invokedMethod, context); } @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeDirect(getInvokedMethod(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeDirect(getInvokedMethod(), context.getHolder()); } @Override @@ -149,8 +151,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInvokeDirect( @@ -159,7 +161,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { if (appView.options().debug) { return true; } @@ -217,8 +219,8 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - DexEncodedMethod method = code.method(); - if (instructionMayHaveSideEffects(appView, method.holder())) { + ProgramMethod context = code.context(); + if (instructionMayHaveSideEffects(appView, context)) { return false; } @@ -236,7 +238,7 @@ if (appView.dexItemFactory().isConstructor(invoke.getInvokedMethod()) && invoke.getReceiver() == getReceiver()) { // If another constructor call than `this` is found, then it must not have side effects. - if (invoke.instructionMayHaveSideEffects(appView, method.holder())) { + if (invoke.instructionMayHaveSideEffects(appView, context)) { return false; } if (otherInitCalls == null) { @@ -267,7 +269,7 @@ } @Override - public AbstractFieldSet readSet(AppView<?> appView, DexType context) { + public AbstractFieldSet readSet(AppView<AppInfoWithLiveness> appView, ProgramMethod context) { DexMethod invokedMethod = getInvokedMethod(); // Trivial instance initializers do not read any fields.
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java index e9f3063..f998009 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; 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.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -86,26 +87,28 @@ } @Override - public DexEncodedMethod lookupSingleTarget(AppView<?> appView, DexType invocationContext) { + public DexEncodedMethod lookupSingleTarget( + AppView<?> appView, ProgramMethod context, Value receiver) { if (appView.appInfo().hasLiveness()) { AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); return appViewWithLiveness .appInfo() .lookupSingleVirtualTarget( getInvokedMethod(), - invocationContext, + context, true, appView, - TypeAnalysis.getRefinedReceiverType(appViewWithLiveness, this), - getReceiver().getDynamicLowerBoundType(appViewWithLiveness)); + TypeAnalysis.getRefinedReceiverType( + appViewWithLiveness, getInvokedMethod(), receiver), + receiver.getDynamicLowerBoundType(appViewWithLiveness)); } return null; } @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeInterface(getInvokedMethod(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeInterface(getInvokedMethod(), context.getHolder()); } @Override @@ -116,8 +119,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInvokeInterface(
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java index 6c9fb6f..8c059d9 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -28,12 +28,9 @@ import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter; import com.android.tools.r8.ir.regalloc.RegisterAllocator; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.SetUtils; -import com.google.common.collect.Sets; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import java.util.BitSet; -import java.util.Collection; import java.util.List; -import java.util.Set; public abstract class InvokeMethod extends Invoke { @@ -76,23 +73,22 @@ // In subclasses, e.g., invoke-virtual or invoke-super, use a narrower receiver type by using // receiver type and calling context---the holder of the method where the current invocation is. // TODO(b/140204899): Refactor lookup methods to be defined in a single place. - public abstract DexEncodedMethod lookupSingleTarget( - AppView<?> appView, DexType invocationContext); + public abstract DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context); public final ProgramMethod lookupSingleProgramTarget(AppView<?> appView, ProgramMethod context) { - DexEncodedMethod singleTarget = lookupSingleTarget(appView, context.getHolderType()); + DexEncodedMethod singleTarget = lookupSingleTarget(appView, context); return singleTarget != null ? singleTarget.asProgramMethod(appView) : null; } // TODO(b/140204899): Refactor lookup methods to be defined in a single place. - public Collection<DexEncodedMethod> lookupTargets( - AppView<AppInfoWithLiveness> appView, DexType invocationContext) { + public ProgramMethodSet lookupProgramDispatchTargets( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { if (!getInvokedMethod().holder.isClassType()) { return null; } if (!isInvokeMethodWithDynamicDispatch()) { - DexEncodedMethod singleTarget = lookupSingleTarget(appView, invocationContext); - return singleTarget != null ? SetUtils.newIdentityHashSet(singleTarget) : null; + ProgramMethod singleTarget = lookupSingleProgramTarget(appView, context); + return singleTarget != null ? ProgramMethodSet.create(singleTarget) : null; } DexProgramClass refinedReceiverUpperBound = asProgramClassOrNull( @@ -113,27 +109,31 @@ refinedReceiverLowerBound = null; } } - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = + appView.appInfo().resolveMethod(method, isInvokeInterface()); LookupResult lookupResult; if (refinedReceiverUpperBound != null) { lookupResult = resolutionResult.lookupVirtualDispatchTargets( - appView.definitionForProgramType(invocationContext), + context.getHolder(), appView.withLiveness().appInfo(), refinedReceiverUpperBound, refinedReceiverLowerBound); } else { lookupResult = resolutionResult.lookupVirtualDispatchTargets( - appView.definitionForProgramType(invocationContext), - appView.withLiveness().appInfo()); + context.getHolder(), appView.withLiveness().appInfo()); } if (lookupResult.isLookupResultFailure()) { return null; } - Set<DexEncodedMethod> result = Sets.newIdentityHashSet(); + ProgramMethodSet result = ProgramMethodSet.create(); lookupResult.forEach( - methodTarget -> result.add(methodTarget.getDefinition()), + methodTarget -> { + if (methodTarget.isProgramMethod()) { + result.add(methodTarget.asProgramMethod()); + } + }, lambda -> { // TODO(b/150277553): Support lambda targets. }); @@ -195,17 +195,18 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return true; } @Override - public AbstractFieldSet readSet(AppView<?> appView, DexType context) { + public AbstractFieldSet readSet(AppView<AppInfoWithLiveness> appView, ProgramMethod context) { return LibraryMethodReadSetModeling.getModeledReadSetOrUnknown(this, appView.dexItemFactory()); } @Override - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { assert hasOutValue(); DexEncodedMethod method = lookupSingleTarget(appView, context); if (method != null) { @@ -224,7 +225,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { DexEncodedMethod singleTarget = lookupSingleTarget(appView, context); if (singleTarget != null) { BitSet nonNullParamOrThrow = singleTarget.getOptimizationInfo().getNonNullParamOrThrow();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java index 00ffbe1..dbee028 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -3,8 +3,11 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.code; +import static com.android.tools.r8.graph.DexEncodedMethod.asProgramMethodOrNull; + import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; @@ -53,7 +56,20 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public final DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) { + return lookupSingleTarget(appView, context, getReceiver()); + } + + public abstract DexEncodedMethod lookupSingleTarget( + AppView<?> appView, ProgramMethod context, Value receiver); + + public final ProgramMethod lookupSingleProgramTarget( + AppView<?> appView, ProgramMethod context, Value receiver) { + return asProgramMethodOrNull(lookupSingleTarget(appView, context, receiver), appView); + } + + @Override + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return value == getReceiver() || super.throwsNpeIfValueIsNull(value, appView, context); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java index 4006bd7..1e41503 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -77,8 +78,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeMultiNewArray(type, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeMultiNewArray(type, context.getHolder()); } @Override @@ -113,7 +114,7 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { DexType baseType = type.isArrayType() ? type.toBaseType(appView.dexItemFactory()) : type; if (baseType.isPrimitiveType()) { // Primitives types are known to be present and accessible. @@ -123,7 +124,7 @@ assert baseType.isReferenceType(); - if (baseType == context) { + if (baseType == context.getHolderType()) { // The enclosing type is known to be present and accessible. return instructionInstanceCanThrowNegativeArraySizeException(); } @@ -172,7 +173,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { // Check if the instruction has a side effect on the locals environment. if (hasOutValue() && outValue().hasLocalInfo()) { assert appView.options().debug; @@ -184,11 +185,11 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java index 3f5a1ab..1d6547e 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -106,8 +107,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeNewArray(type, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeNewArray(type, context.getHolder()); } @Override @@ -140,7 +141,7 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { DexType baseType = type.isArrayType() ? type.toBaseType(appView.dexItemFactory()) : type; if (baseType.isPrimitiveType()) { // Primitives types are known to be present and accessible. @@ -150,7 +151,7 @@ assert baseType.isReferenceType(); - if (baseType == context) { + if (baseType == context.getHolderType()) { // The enclosing type is known to be present and accessible. return AbstractError.bottom(); } @@ -185,7 +186,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { // Check if the instruction has a side effect on the locals environment. if (hasOutValue() && outValue().hasLocalInfo()) { assert appView.options().debug; @@ -197,11 +198,11 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java index 8d46da1..6a1e8a2 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -23,7 +23,7 @@ import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import java.util.Collection; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import java.util.List; public class InvokePolymorphic extends InvokeMethod { @@ -120,22 +120,22 @@ } @Override - public DexEncodedMethod lookupSingleTarget(AppView<?> appView, DexType invocationContext) { + public DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) { // TODO(herhut): Implement lookup target for invokePolymorphic. return null; } @Override - public Collection<DexEncodedMethod> lookupTargets( - AppView<AppInfoWithLiveness> appView, DexType invocationContext) { + public ProgramMethodSet lookupProgramDispatchTargets( + AppView<AppInfoWithLiveness> appView, ProgramMethod context) { // TODO(herhut): Implement lookup target for invokePolymorphic. return null; } @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokePolymorphic(getInvokedMethod(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokePolymorphic(getInvokedMethod(), context.getHolder()); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java index 5ea6e46..2c5faaf 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -103,13 +103,13 @@ } @Override - public DexEncodedMethod lookupSingleTarget(AppView<?> appView, DexType invocationContext) { + public DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) { DexMethod invokedMethod = getInvokedMethod(); if (appView.appInfo().hasLiveness()) { AppInfoWithLiveness appInfo = appView.appInfo().withLiveness(); - DexEncodedMethod result = appInfo.lookupStaticTarget(invokedMethod, invocationContext); + DexEncodedMethod result = appInfo.lookupStaticTarget(invokedMethod, context); assert verifyD8LookupResult( - result, appView.appInfo().lookupStaticTargetOnItself(invokedMethod, invocationContext)); + result, appView.appInfo().lookupStaticTargetOnItself(invokedMethod, context)); return result; } // Allow optimizing static library invokes in D8. @@ -120,13 +120,13 @@ } // In D8, we can treat invoke-static instructions as having a single target if the invoke is // targeting a method in the enclosing class. - return appView.appInfo().lookupStaticTargetOnItself(invokedMethod, invocationContext); + return appView.appInfo().lookupStaticTargetOnItself(invokedMethod, context); } @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeStatic(getInvokedMethod(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeStatic(getInvokedMethod(), context.getHolder()); } @Override @@ -148,8 +148,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInvokeStatic( @@ -158,7 +158,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { if (!appView.enableWholeProgramOptimizations()) { return true; } @@ -207,7 +207,7 @@ appView, // Types that are a super type of `context` are guaranteed to be initialized // already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet()); } @@ -216,6 +216,6 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java index 588a0f1..e2b2e3a 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; 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.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -93,12 +94,13 @@ } @Override - public DexEncodedMethod lookupSingleTarget(AppView<?> appView, DexType invocationContext) { - if (appView.appInfo().hasLiveness() && invocationContext != null) { + public DexEncodedMethod lookupSingleTarget( + AppView<?> appView, ProgramMethod context, Value receiver) { + if (appView.appInfo().hasLiveness() && context != null) { AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); AppInfoWithLiveness appInfo = appViewWithLiveness.appInfo(); - if (appInfo.isSubtype(invocationContext, getInvokedMethod().holder)) { - return appInfo.lookupSuperTarget(getInvokedMethod(), invocationContext); + if (appInfo.isSubtype(context.getHolderType(), getInvokedMethod().holder)) { + return appInfo.lookupSuperTarget(getInvokedMethod(), context); } } return null; @@ -106,15 +108,15 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeSuper(getInvokedMethod(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeSuper(getInvokedMethod(), context.getHolder()); } @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInvokeSuper(
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java index b9a0765..69111fc 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java +++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; 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.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -90,19 +91,20 @@ } @Override - public DexEncodedMethod lookupSingleTarget(AppView<?> appView, DexType invocationContext) { - return lookupSingleTarget(appView, invocationContext, getInvokedMethod(), getReceiver()); + public DexEncodedMethod lookupSingleTarget( + AppView<?> appView, ProgramMethod context, Value receiver) { + return lookupSingleTarget(appView, context, receiver, getInvokedMethod()); } public static DexEncodedMethod lookupSingleTarget( - AppView<?> appView, DexType invocationContext, DexMethod method, Value receiver) { + AppView<?> appView, ProgramMethod context, Value receiver, DexMethod method) { if (appView.appInfo().hasLiveness()) { AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); return appViewWithLiveness .appInfo() .lookupSingleVirtualTarget( method, - invocationContext, + context, false, appView, TypeAnalysis.getRefinedReceiverType(appViewWithLiveness, method, receiver), @@ -126,8 +128,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forInvokeVirtual(getInvokedMethod(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forInvokeVirtual(getInvokedMethod(), context.getHolder()); } @Override @@ -138,8 +140,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forInvokeVirtual( @@ -148,7 +150,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { if (!appView.enableWholeProgramOptimizations()) { return true; } @@ -205,6 +207,6 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java index 8e1e347..9536919 100644 --- a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.ir.code; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import java.util.List; @@ -48,7 +48,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forJumpInstruction(); } @@ -58,7 +58,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Load.java b/src/main/java/com/android/tools/r8/ir/code/Load.java index 9886690..eee3bef 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Load.java +++ b/src/main/java/com/android/tools/r8/ir/code/Load.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -63,7 +64,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forLoad(); } @@ -99,7 +100,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Monitor.java b/src/main/java/com/android/tools/r8/ir/code/Monitor.java index 598bc6c..f779651 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Monitor.java +++ b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
@@ -12,7 +12,7 @@ import com.android.tools.r8.code.MonitorExit; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -109,7 +109,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forMonitor(); } @@ -141,7 +141,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { return object() == value; } @@ -156,7 +156,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Move.java b/src/main/java/com/android/tools/r8/ir/code/Move.java index 24e831c..f531071 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Move.java +++ b/src/main/java/com/android/tools/r8/ir/code/Move.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -99,7 +99,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forMove(); } @@ -119,7 +119,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java index 9f21f17..4c87b70 100644 --- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java +++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -8,6 +8,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -87,7 +88,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forMoveException(); } @@ -121,7 +122,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java index bd5c34f..c730efc 100644 --- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java +++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; @@ -107,8 +108,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forNewArrayEmpty(type, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forNewArrayEmpty(type, context.getHolder()); } @Override @@ -139,7 +140,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java index fd6cf65..aaa27dd 100644 --- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java +++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AbstractError; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -101,7 +101,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forNewArrayFilledData(); } @@ -116,7 +116,7 @@ } @Override - public AbstractError instructionInstanceCanThrow(AppView<?> appView, DexType context) { + public AbstractError instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) { if (appView.options().debug) { return AbstractError.top(); } @@ -130,7 +130,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { // Treat the instruction as possibly having side-effects if it may throw or the array is used. if (instructionInstanceCanThrow(appView, context).isThrowing() || src().numberOfAllUsers() > 1) { @@ -145,12 +145,12 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java index e30cdf1..3e6c121 100644 --- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java +++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -14,6 +14,7 @@ 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.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; @@ -24,6 +25,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.google.common.collect.Sets; public class NewInstance extends Instruction { @@ -100,8 +102,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forNewInstance(clazz, invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forNewInstance(clazz, context.getHolder()); } @Override @@ -132,8 +134,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forNewInstance( @@ -142,13 +144,16 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { DexItemFactory dexItemFactory = appView.dexItemFactory(); if (!appView.enableWholeProgramOptimizations()) { return !(dexItemFactory.libraryTypesAssumedToBePresent.contains(clazz) && dexItemFactory.libraryClassesWithoutStaticInitialization.contains(clazz)); } + assert appView.appInfo().hasLiveness(); + AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); + if (clazz.isPrimitiveType() || clazz.isArrayType()) { assert false : "Unexpected new-instance instruction with primitive or array type"; return true; @@ -165,9 +170,8 @@ } // Verify that the instruction does not lead to an IllegalAccessError. - if (appView.appInfo().hasLiveness() - && !isMemberVisibleFromOriginalContext( - appView, context, definition.type, definition.accessFlags)) { + if (!isMemberVisibleFromOriginalContext( + appView, context, definition.type, definition.accessFlags)) { return true; } @@ -175,14 +179,16 @@ if (definition.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appViewWithLiveness.appInfo().isSubtype(context.getHolderType(), type), Sets.newIdentityHashSet())) { return true; } // Verify that the object does not have a finalizer. ResolutionResult finalizeResolutionResult = - appView.appInfo().resolveMethod(clazz, dexItemFactory.objectMembers.finalize); + appViewWithLiveness + .appInfo() + .resolveMethodOnClass(dexItemFactory.objectMembers.finalize, clazz); if (finalizeResolutionResult.isSingleResolution()) { DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().method; if (finalizeMethod != dexItemFactory.enumMethods.finalize @@ -196,7 +202,7 @@ @Override public boolean canBeDeadCode(AppView<?> appView, IRCode code) { - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } public void markNoSpilling() { @@ -208,19 +214,19 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { if (appView.enableWholeProgramOptimizations()) { // In R8, check if the class initialization of the holder or any of its ancestor types may // have side effects. return clazz.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet()); } else { // In D8, this instruction may trigger class initialization if the holder of the field is // different from the current context. - return clazz != context; + return clazz != context.getHolderType(); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Pop.java b/src/main/java/com/android/tools/r8/ir/code/Pop.java index ab07480..0124c45 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Pop.java +++ b/src/main/java/com/android/tools/r8/ir/code/Pop.java
@@ -7,7 +7,7 @@ import com.android.tools.r8.cf.code.CfStackInstruction; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -66,7 +66,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forPop(); } @@ -97,7 +97,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java index 0adf292..19c9887 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Return.java +++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -11,7 +11,7 @@ import com.android.tools.r8.code.ReturnWide; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -110,7 +110,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forReturn(); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticFieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/StaticFieldInstruction.java index 286b470..9b0e28a 100644 --- a/src/main/java/com/android/tools/r8/ir/code/StaticFieldInstruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/StaticFieldInstruction.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.ir.code; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Instruction.SideEffectAssumption; public interface StaticFieldInstruction { @@ -14,10 +14,10 @@ Value outValue(); - boolean instructionMayHaveSideEffects(AppView<?> appView, DexType context); + boolean instructionMayHaveSideEffects(AppView<?> appView, ProgramMethod context); boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption); + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption); FieldInstruction asFieldInstruction();
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java index de66cba..e0e8b63 100644 --- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java +++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -27,6 +28,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.google.common.collect.Sets; import java.util.Set; @@ -136,13 +138,13 @@ } @Override - public boolean instructionMayHaveSideEffects(AppView<?> appView, DexType context) { + public boolean instructionMayHaveSideEffects(AppView<?> appView, ProgramMethod context) { return instructionMayHaveSideEffects(appView, context, SideEffectAssumption.NONE); } @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { return instructionInstanceCanThrow(appView, context, assumption).isThrowing(); } @@ -153,7 +155,7 @@ // * IncompatibleClassChangeError (static-* instruction for instance fields) // * IllegalAccessError (not visible from the access context) // * side-effects in <clinit> - return !instructionMayHaveSideEffects(appView, code.method().holder()); + return !instructionMayHaveSideEffects(appView, code.context()); } @Override @@ -177,8 +179,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forStaticGet(getField(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forStaticGet(getField(), context.getHolder()); } @Override @@ -226,8 +228,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forStaticGet( @@ -240,7 +242,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { DexType holder = getField().holder; if (appView.enableWholeProgramOptimizations()) { // In R8, check if the class initialization of the holder or any of its ancestor types may @@ -248,12 +250,12 @@ return holder.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet()); } else { // In D8, this instruction may trigger class initialization if the holder of the field is // different from the current context. - return holder != context; + return holder != context.getHolderType(); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java index 78d4de9..11732a9 100644 --- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java +++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query; @@ -95,7 +96,7 @@ @Override public boolean instructionMayHaveSideEffects( - AppView<?> appView, DexType context, SideEffectAssumption assumption) { + AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) { if (appView.appInfo().hasLiveness()) { AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo(); @@ -113,7 +114,8 @@ return true; } - DexEncodedField encodedField = appInfoWithLiveness.resolveField(getField()); + DexEncodedField encodedField = + appInfoWithLiveness.resolveField(getField()).getResolvedField(); assert encodedField != null : "NoSuchFieldError (resolution failure) should be caught."; boolean isDeadProtoExtensionField = @@ -139,7 +141,7 @@ // * IllegalAccessError (not visible from the access context) // * side-effects in <clinit> // * not read _globally_ - boolean haveSideEffects = instructionMayHaveSideEffects(appView, code.method().holder()); + boolean haveSideEffects = instructionMayHaveSideEffects(appView, code.context()); assert appView.enableWholeProgramOptimizations() || haveSideEffects : "Expected static-put instruction to have side effects in D8"; return !haveSideEffects; @@ -187,8 +189,8 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { - return inliningConstraints.forStaticPut(getField(), invocationContext); + InliningConstraints inliningConstraints, ProgramMethod context) { + return inliningConstraints.forStaticPut(getField(), context.getHolder()); } @Override @@ -226,8 +228,8 @@ @Override public boolean definitelyTriggersClassInitialization( DexType clazz, - DexType context, - AppView<?> appView, + ProgramMethod context, + AppView<AppInfoWithLiveness> appView, Query mode, AnalysisAssumption assumption) { return ClassInitializationAnalysis.InstructionUtils.forStaticPut( @@ -235,7 +237,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { DexType holder = getField().holder; if (appView.enableWholeProgramOptimizations()) { // In R8, check if the class initialization of the holder or any of its ancestor types may @@ -243,12 +245,12 @@ return holder.classInitializationMayHaveSideEffects( appView, // Types that are a super type of `context` are guaranteed to be initialized already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(context.getHolderType(), type).isTrue(), Sets.newIdentityHashSet()); } else { // In D8, this instruction may trigger class initialization if the holder of the field is // different from the current context. - return holder != context; + return holder != context.getHolderType(); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java index 4fe63c0..ccd57ea 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Store.java +++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -64,7 +65,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forStore(); } @@ -111,7 +112,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Swap.java b/src/main/java/com/android/tools/r8/ir/code/Swap.java index 2515934..5dfa623 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Swap.java +++ b/src/main/java/com/android/tools/r8/ir/code/Swap.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; @@ -89,7 +89,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forSwap(); } @@ -114,7 +114,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java index 2b6b80d..6f47788 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Throw.java +++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -7,7 +7,7 @@ import com.android.tools.r8.cf.code.CfThrow; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; @@ -72,7 +72,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forThrow(); } @@ -87,7 +87,7 @@ } @Override - public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, DexType context) { + public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) { if (exception() == value) { return true; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Unop.java b/src/main/java/com/android/tools/r8/ir/code/Unop.java index 1765626..9c65c4e 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Unop.java +++ b/src/main/java/com/android/tools/r8/ir/code/Unop.java
@@ -6,7 +6,7 @@ import com.android.tools.r8.cf.LoadStoreHelper; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; @@ -47,7 +47,7 @@ @Override public ConstraintWithTarget inliningConstraint( - InliningConstraints inliningConstraints, DexType invocationContext) { + InliningConstraints inliningConstraints, ProgramMethod context) { return inliningConstraints.forUnop(); } @@ -68,7 +68,7 @@ } @Override - public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, DexType context) { + public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java index bbe7f7f..02ab2d9 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Value.java +++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -20,6 +20,7 @@ import com.android.tools.r8.graph.DexClass; 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.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; @@ -891,7 +892,7 @@ return definition.isOutConstant() && !hasLocalInfo(); } - public AbstractValue getAbstractValue(AppView<?> appView, DexType context) { + public AbstractValue getAbstractValue(AppView<?> appView, ProgramMethod context) { if (!appView.enableWholeProgramOptimizations()) { return UnknownValue.getInstance(); } @@ -901,7 +902,7 @@ return UnknownValue.getInstance(); } - return root.definition.getAbstractValue(appView, context); + return root.definition.getAbstractValue(appView.withLiveness(), context); } public boolean isDefinedByInstructionSatisfying(Predicate<Instruction> predicate) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java index e6bd8bf..9f57ac1 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -165,25 +165,25 @@ } private void processInvoke(Invoke.Type originalType, DexMethod originalMethod) { - ProgramMethod source = currentMethod.getProgramMethod(); - DexMethod context = source.getReference(); + ProgramMethod context = currentMethod.getProgramMethod(); GraphLenseLookupResult result = - appView.graphLense().lookupMethod(originalMethod, context, originalType); + appView.graphLense().lookupMethod(originalMethod, context.getReference(), originalType); DexMethod method = result.getMethod(); Invoke.Type type = result.getType(); if (type == Invoke.Type.INTERFACE || type == Invoke.Type.VIRTUAL) { // For virtual and interface calls add all potential targets that could be called. - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = + appView.appInfo().resolveMethod(method, type == Invoke.Type.INTERFACE); DexEncodedMethod target = resolutionResult.getSingleTarget(); if (target != null) { - processInvokeWithDynamicDispatch(type, target, context.holder); + processInvokeWithDynamicDispatch(type, target, context); } } else { ProgramMethod singleTarget = - appView.appInfo().lookupSingleProgramTarget(type, method, context.holder, appView); + appView.appInfo().lookupSingleProgramTarget(type, method, context, appView); if (singleTarget != null) { - assert !source.getDefinition().isBridge() - || singleTarget.getDefinition() != source.getDefinition(); + assert !context.getDefinition().isBridge() + || singleTarget.getDefinition() != context.getDefinition(); // For static invokes, the class could be initialized. if (type == Invoke.Type.STATIC) { addClassInitializerTarget(singleTarget.getHolder()); @@ -194,7 +194,7 @@ } private void processInvokeWithDynamicDispatch( - Invoke.Type type, DexEncodedMethod encodedTarget, DexType context) { + Invoke.Type type, DexEncodedMethod encodedTarget, ProgramMethod context) { DexMethod target = encodedTarget.method; DexClass clazz = appView.definitionFor(target.holder); if (clazz == null) { @@ -214,12 +214,11 @@ possibleProgramTargetsCache.computeIfAbsent( target, method -> { - ResolutionResult resolution = - appView.appInfo().resolveMethod(method.holder, method, isInterface); + ResolutionResult resolution = appView.appInfo().resolveMethod(method, isInterface); if (resolution.isVirtualTarget()) { LookupResult lookupResult = resolution.lookupVirtualDispatchTargets( - appView.definitionForProgramType(context), appView.appInfo()); + context.getHolder(), appView.appInfo()); if (lookupResult.isLookupResultSuccess()) { ProgramMethodSet targets = ProgramMethodSet.create(); lookupResult @@ -258,7 +257,7 @@ return; } - DexEncodedField encodedField = appView.appInfo().resolveField(field); + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField == null || appView.appInfo().isPinned(encodedField.field)) { return; } @@ -283,7 +282,7 @@ private void processFieldWrite(DexField field) { if (field.holder.isClassType()) { - DexEncodedField encodedField = appView.appInfo().resolveField(field); + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField != null && encodedField.isStatic()) { // Each static field access implicitly triggers the class initializer. addClassInitializerTarget(field.holder);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java index 74f24c8..00eb737 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -183,7 +183,8 @@ } public DexField resolveField(DexField field) { - DexEncodedField resolvedField = appView.appInfo().resolveField(field); + DexEncodedField resolvedField = + appView.appInfoForDesugaring().resolveField(field).getResolvedField(); return resolvedField == null ? field : resolvedField.field; }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java index 31fd3c0..14a936d 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -290,13 +290,13 @@ if (options.testing.forceAssumeNoneInsertion) { assumers.add(new AliasIntroducer(appView)); } - if (options.enableNonNullTracking) { - assumers.add(new NonNullTracker(appView)); - } if (appView.enableWholeProgramOptimizations()) { assert appView.appInfo().hasLiveness(); assert appView.rootSet() != null; AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); + if (options.enableNonNullTracking) { + assumers.add(new NonNullTracker(appViewWithLiveness)); + } this.classInliner = options.enableClassInlining && options.enableInlining ? new ClassInliner() : null; this.classStaticizer = @@ -1164,7 +1164,7 @@ } else { if (lambdaRewriter != null) { timing.begin("Desugar lambdas"); - lambdaRewriter.desugarLambdas(method, code); + lambdaRewriter.desugarLambdas(code); timing.end(); assert code.isConsistentSSA(); } @@ -1284,7 +1284,7 @@ if (devirtualizer != null) { assert code.verifyTypes(appView); timing.begin("Devirtualize invoke interface"); - devirtualizer.devirtualizeInvokeInterface(code, holder); + devirtualizer.devirtualizeInvokeInterface(code); timing.end(); } @@ -1372,7 +1372,7 @@ timing.begin("Optimize class initializers"); ClassInitializerDefaultsResult classInitializerDefaultsResult = - classInitializerDefaultsOptimization.optimize(method, code, feedback); + classInitializerDefaultsOptimization.optimize(code, feedback); timing.end(); if (Log.ENABLED) { @@ -1585,6 +1585,11 @@ timing.end(); } + if (appView.isCfByteCodePassThrough(method)) { + // If the code is pass trough, do not finalize by overwriting the existing code. + return timing; + } + printMethod(code, "Optimized IR (SSA)", previous); timing.begin("Finalize IR"); finalizeIR(code, feedback, timing); @@ -1632,11 +1637,11 @@ if (method.isInitializer()) { if (method.isClassInitializer()) { StaticFieldValueAnalysis.run( - appView, code, classInitializerDefaultsResult, feedback, code.method(), timing); + appView, code, classInitializerDefaultsResult, feedback, timing); } else { instanceFieldInitializationInfos = InstanceFieldValueAnalysis.run( - appView, code, classInitializerDefaultsResult, feedback, code.method(), timing); + appView, code, classInitializerDefaultsResult, feedback, timing); } } methodOptimizationInfoCollector.collectMethodOptimizationInfo( @@ -1711,7 +1716,7 @@ ProgramMethod method = code.context(); ConstraintWithTarget state = shouldComputeInliningConstraint(method) - ? inliner.computeInliningConstraint(code, method) + ? inliner.computeInliningConstraint(code) : ConstraintWithTarget.NEVER; feedback.markProcessed(method.getDefinition(), state); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java index e9aed7f..e059db8 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -10,7 +10,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppInfo; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.Code; @@ -108,7 +107,7 @@ if (androidApp != null) { DexApplication app = new ApplicationReader(androidApp, options, Timing.empty()).read(executor); - appInfo = new AppInfoWithClassHierarchy(app); + appInfo = new AppInfo(app); } AppView<?> appView = AppView.createForD8(appInfo, options, rewritePrefix); BackportedMethodRewriter.RewritableMethods rewritableMethods =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java index 47ee95f..72f630b 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -171,7 +171,7 @@ } } - private final AppView<? extends AppInfoWithClassHierarchy> appView; + private final AppView<?> appView; private final DexItemFactory dexItemFactory; private final InterfaceMethodRewriter rewriter; private final Consumer<ProgramMethod> newSynthesizedMethodConsumer; @@ -192,7 +192,7 @@ new IdentityHashMap<>(); ClassProcessor( - AppView<? extends AppInfoWithClassHierarchy> appView, + AppView<?> appView, InterfaceMethodRewriter rewriter, Consumer<ProgramMethod> newSynthesizedMethodConsumer) { this.appView = appView; @@ -283,14 +283,14 @@ // Doing so can cause an invalid invoke to become valid (at runtime resolution at a subtype // might have failed which is hidden by the insertion of the forward method). However, not doing // so could cause valid dispatches to become invalid by resolving to private overrides. + AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring(); DexClassAndMethod virtualDispatchTarget = - appView - .appInfo() + appInfo .resolveMethodOnInterface(method.holder, method) - .lookupVirtualDispatchTarget(clazz, appView.appInfo()); + .lookupVirtualDispatchTarget(clazz, appInfo); if (virtualDispatchTarget == null) { // If no target is found due to multiple default method targets, preserve ICCE behavior. - ResolutionResult resolutionFromSubclass = appView.appInfo().resolveMethod(clazz, method); + ResolutionResult resolutionFromSubclass = appInfo.resolveMethodOn(clazz, method); if (resolutionFromSubclass.isIncompatibleClassChangeErrorResult()) { addICCEThrowingMethod(method, clazz); return; @@ -327,8 +327,7 @@ // If target is a non-interface library class it may be an emulated interface. if (!libraryHolder.isInterface()) { // Here we use step-3 of resolution to find a maximally specific default interface method. - DexClassAndMethod result = - appView.appInfo().lookupMaximallySpecificMethod(libraryHolder, method); + DexClassAndMethod result = appInfo.lookupMaximallySpecificMethod(libraryHolder, method); if (result != null && rewriter.isEmulatedInterface(result.getHolder().type)) { addForward.accept(result.getHolder(), result.getDefinition()); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java index a640fb6..408b152 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.ir.desugar; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.DexAnnotationSet; @@ -49,7 +48,7 @@ public static final String DESUGAR_LIB_RETARGET_CLASS_NAME_PREFIX = "$r8$retargetLibraryMember$virtualDispatch"; - private final AppView<AppInfoWithClassHierarchy> appView; + private final AppView<?> appView; private final Map<DexMethod, DexMethod> retargetLibraryMember = new IdentityHashMap<>(); // Map virtualRewrites hold a methodName->method mapping for virtual methods which are // rewritten while the holder is non final but no superclass implement the method. In this case @@ -59,9 +58,7 @@ private final Set<DexMethod> emulatedDispatchMethods = Sets.newHashSet(); public DesugaredLibraryRetargeter(AppView<?> appView) { - assert appView.appInfo().hasClassHierarchy() - : "Class hierarchy required for desugared library."; - this.appView = appView.withClassHierarchy(); + this.appView = appView; if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) { return; } @@ -116,8 +113,8 @@ // We need to force resolution, even on d8, to know if the invoke has to be rewritten. ResolutionResult resolutionResult = appView - .appInfo() - .resolveMethod(invoke.getInvokedMethod().holder, invoke.getInvokedMethod()); + .appInfoForDesugaring() + .resolveMethod(invoke.getInvokedMethod(), invoke.isInvokeInterface()); if (resolutionResult.isFailedResolution()) { continue; } @@ -134,9 +131,8 @@ if (invoke.isInvokeSuper() && matchesVirtualRewrite(invoke.getInvokedMethod())) { DexEncodedMethod dexEncodedMethod = appView - .appInfo() - .withClassHierarchy() - .lookupSuperTarget(invoke.getInvokedMethod(), code.method().holder()); + .appInfoForDesugaring() + .lookupSuperTarget(invoke.getInvokedMethod(), code.context()); // Final methods can be rewritten as a normal invoke. if (dexEncodedMethod != null && !dexEncodedMethod.isFinal()) { DexMethod retargetMethod =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java index e3c15ae..5fbf3df 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -99,7 +99,8 @@ public static final String VIVIFIED_TYPE_WRAPPER_SUFFIX = "$-V-WRP"; private final AppView<?> appView; - private final DexString dexWrapperPrefix; + private final String dexWrapperPrefixString; + private final DexString dexWrapperPrefixDexString; private final Map<DexType, DexType> typeWrappers = new ConcurrentHashMap<>(); private final Map<DexType, DexType> vivifiedTypeWrappers = new ConcurrentHashMap<>(); // The invalidWrappers are wrappers with incorrect behavior because of final methods that could @@ -114,13 +115,14 @@ DesugaredLibraryWrapperSynthesizer(AppView<?> appView, DesugaredLibraryAPIConverter converter) { this.appView = appView; this.factory = appView.dexItemFactory(); - this.dexWrapperPrefix = factory.createString("L" + WRAPPER_PREFIX); + dexWrapperPrefixString = "L" + appView.options().synthesizedClassPrefix + WRAPPER_PREFIX; + dexWrapperPrefixDexString = factory.createString(dexWrapperPrefixString); this.converter = converter; this.vivifiedSourceFile = appView.dexItemFactory().createString("vivified"); } boolean hasSynthesized(DexType type) { - return type.descriptor.startsWith(dexWrapperPrefix); + return type.descriptor.startsWith(dexWrapperPrefixDexString); } boolean canGenerateWrapper(DexType type) { @@ -145,12 +147,7 @@ private DexType createWrapperType(DexType type, String suffix) { return factory.createType( - "L" - + appView.options().synthesizedClassPrefix - + WRAPPER_PREFIX - + type.toString().replace('.', '$') - + suffix - + ";"); + dexWrapperPrefixString + type.toString().replace('.', '$') + suffix + ";"); } private DexType getWrapper(DexType type, String suffix, Map<DexType, DexType> wrappers) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java index 5d494bb..1f6af29 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -8,7 +8,6 @@ import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.graph.AppInfo; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.DexAnnotationSet; @@ -102,7 +101,7 @@ public static final String DEFAULT_METHOD_PREFIX = "$default$"; public static final String PRIVATE_METHOD_PREFIX = "$private$"; - private final AppView<? extends AppInfoWithClassHierarchy> appView; + private final AppView<?> appView; private final IRConverter converter; private final InternalOptions options; final DexItemFactory factory; @@ -137,9 +136,7 @@ public InterfaceMethodRewriter(AppView<?> appView, IRConverter converter) { assert converter != null; - assert appView.appInfo().hasClassHierarchy() - : "Cannot desugar interfaces without class hierarchy"; - this.appView = appView.withClassHierarchy(); + this.appView = appView; this.converter = converter; this.options = appView.options(); this.factory = appView.dexItemFactory(); @@ -316,8 +313,8 @@ // If it resolves to a program overrides, the invoke-super can remain. DexEncodedMethod dexEncodedMethod = appView - .appInfo() - .lookupSuperTarget(invokeSuper.getInvokedMethod(), code.method().holder()); + .appInfoForDesugaring() + .lookupSuperTarget(invokeSuper.getInvokedMethod(), code.context()); if (dexEncodedMethod != null) { DexClass dexClass = appView.definitionFor(dexEncodedMethod.holder()); if (dexClass != null && dexClass.isLibraryClass()) { @@ -390,7 +387,7 @@ } else { // The method can be a default method in the interface hierarchy. DexClassAndMethod virtualTarget = - appView.appInfo().lookupMaximallySpecificMethod(clazz, method); + appView.appInfoForDesugaring().lookupMaximallySpecificMethod(clazz, method); if (virtualTarget != null) { // This is a invoke-direct call to a virtual method. instructions.replaceCurrentInstruction( @@ -448,7 +445,7 @@ } if (singleTarget == null) { DexClassAndMethod result = - appView.appInfo().lookupMaximallySpecificMethod(dexClass, invokedMethod); + appView.appInfoForDesugaring().lookupMaximallySpecificMethod(dexClass, invokedMethod); if (result != null) { singleTarget = result.getDefinition(); } @@ -1123,7 +1120,7 @@ DexMethod method = appView.graphLense().getOriginalMethodSignature(referencedFrom); Origin origin = getMethodOrigin(method); MethodPosition position = new MethodPosition(method); - options.warningMissingTypeForDesugar(origin, position, missing, method.holder); + options.warningMissingTypeForDesugar(origin, position, missing, method); } private Origin getMethodOrigin(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java index 05c9c66..7ed2773 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexClass; @@ -61,6 +62,7 @@ */ public final class LambdaClass { + final AppView<?> appView; final LambdaRewriter rewriter; public final DexType type; public LambdaDescriptor descriptor; @@ -74,19 +76,21 @@ Suppliers.memoize(this::synthesizeLambdaClass); // NOTE: thread-safe. LambdaClass( + AppView<?> appView, LambdaRewriter rewriter, - DexType accessedFrom, + ProgramMethod accessedFrom, DexType lambdaClassType, LambdaDescriptor descriptor) { assert rewriter != null; assert lambdaClassType != null; assert descriptor != null; + this.appView = appView; this.rewriter = rewriter; this.type = lambdaClassType; this.descriptor = descriptor; - DexItemFactory factory = rewriter.getFactory(); + DexItemFactory factory = appView.dexItemFactory(); DexProto constructorProto = factory.createProto( factory.voidType, descriptor.captures.values); this.constructor = @@ -107,17 +111,12 @@ } // Generate unique lambda class type for lambda descriptor and instantiation point context. - static DexType createLambdaClassType( - LambdaRewriter rewriter, DexType accessedFrom, LambdaDescriptor match) { - return createLambdaClassType(rewriter.getFactory(), accessedFrom, match); - } - public static DexType createLambdaClassType( - DexItemFactory factory, DexType accessedFrom, LambdaDescriptor match) { + AppView<?> appView, ProgramMethod accessedFrom, LambdaDescriptor match) { StringBuilder lambdaClassDescriptor = new StringBuilder("L"); // We always create lambda class in the same package where it is referenced. - String packageDescriptor = accessedFrom.getPackageDescriptor(); + String packageDescriptor = accessedFrom.getHolderType().getPackageDescriptor(); if (!packageDescriptor.isEmpty()) { lambdaClassDescriptor.append(packageDescriptor).append('/'); } @@ -129,12 +128,12 @@ // just add the name of this type to make lambda class name unique. // It also helps link the class lambda originated from in some cases. if (match.delegatesToLambdaImplMethod() || match.needsAccessor(accessedFrom)) { - lambdaClassDescriptor.append(accessedFrom.getName()).append('$'); + lambdaClassDescriptor.append(accessedFrom.getHolderType().getName()).append('$'); } // Add unique lambda descriptor id lambdaClassDescriptor.append(match.uniqueId).append(';'); - return factory.createType(lambdaClassDescriptor.toString()); + return appView.dexItemFactory().createType(lambdaClassDescriptor.toString()); } public final DexProgramClass getOrCreateLambdaClass() { @@ -143,7 +142,7 @@ private DexProgramClass synthesizeLambdaClass() { DexMethod mainMethod = - rewriter.getFactory().createMethod(type, descriptor.erasedProto, descriptor.name); + appView.dexItemFactory().createMethod(type, descriptor.erasedProto, descriptor.name); DexProgramClass clazz = new DexProgramClass( @@ -154,9 +153,9 @@ // classloader (package private access is not allowed across classloaders, b/72538146). ClassAccessFlags.fromDexAccessFlags( Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC), - rewriter.getFactory().objectType, + appView.dexItemFactory().objectType, buildInterfaces(), - rewriter.getFactory().createString("lambda"), + appView.dexItemFactory().createString("lambda"), null, Collections.emptyList(), null, @@ -166,9 +165,9 @@ synthesizeInstanceFields(), synthesizeDirectMethods(), synthesizeVirtualMethods(mainMethod), - rewriter.getFactory().getSkipNameValidationForTesting(), + appView.dexItemFactory().getSkipNameValidationForTesting(), LambdaClass::computeChecksumForSynthesizedClass); - rewriter.getAppInfo().addSynthesizedClass(clazz); + appView.appInfo().addSynthesizedClass(clazz); // The method addSynthesizedFrom() may be called concurrently. To avoid a Concurrent- // ModificationException we must use synchronization. @@ -197,12 +196,12 @@ } final DexField getCaptureField(int index) { - return rewriter - .getFactory() + return appView + .dexItemFactory() .createField( this.type, descriptor.captures.values[index], - rewriter.getFactory().createString("f$" + index)); + appView.dexItemFactory().createString("f$" + index)); } public final boolean isStateless() { @@ -239,7 +238,7 @@ // Synthesize bridge methods. for (DexProto bridgeProto : descriptor.bridges) { DexMethod bridgeMethod = - rewriter.getFactory().createMethod(type, bridgeProto, descriptor.name); + appView.dexItemFactory().createMethod(type, bridgeProto, descriptor.name); methods[index++] = new DexEncodedMethod( bridgeMethod, @@ -337,7 +336,7 @@ // Creates a delegation target for this particular lambda class. Note that we // should always be able to create targets for the lambdas we support. - private Target createTarget(DexType accessedFrom) { + private Target createTarget(ProgramMethod accessedFrom) { if (descriptor.delegatesToLambdaImplMethod()) { return createLambdaImplMethodTarget(accessedFrom); } @@ -360,17 +359,20 @@ } } - private Target createLambdaImplMethodTarget(DexType accessedFrom) { + private Target createLambdaImplMethodTarget(ProgramMethod accessedFrom) { DexMethodHandle implHandle = descriptor.implHandle; assert implHandle != null; DexMethod implMethod = implHandle.asMethod(); // Lambda$ method. We must always find it. - assert implMethod.holder == accessedFrom; - assert descriptor.verifyTargetFoundInClass(accessedFrom); + assert implMethod.holder == accessedFrom.getHolderType(); + assert descriptor.verifyTargetFoundInClass(accessedFrom.getHolderType()); if (implHandle.type.isInvokeStatic()) { SingleResolutionResult resolution = - rewriter.getAppInfo().resolveMethod(implMethod.holder, implMethod).asSingleResolution(); + appView + .appInfoForDesugaring() + .resolveMethod(implMethod, implHandle.isInterface) + .asSingleResolution(); assert resolution.getResolvedMethod().isStatic(); assert resolution.getResolvedHolder().isProgramClass(); return new StaticLambdaImplTarget( @@ -383,28 +385,28 @@ // If the lambda$ method is an instance-private method on an interface we convert it into a // public static method as it will be placed on the companion class. if (implHandle.type.isInvokeDirect() - && rewriter.getAppView().definitionFor(implMethod.holder).isInterface()) { + && appView.definitionFor(implMethod.holder).isInterface()) { DexProto implProto = implMethod.proto; DexType[] implParams = implProto.parameters.values; DexType[] newParams = new DexType[implParams.length + 1]; newParams[0] = implMethod.holder; System.arraycopy(implParams, 0, newParams, 1, implParams.length); - DexProto newProto = rewriter.getFactory().createProto(implProto.returnType, newParams); + DexProto newProto = appView.dexItemFactory().createProto(implProto.returnType, newParams); return new InterfaceLambdaImplTarget( - rewriter.getFactory().createMethod(implMethod.holder, newProto, implMethod.name)); + appView.dexItemFactory().createMethod(implMethod.holder, newProto, implMethod.name)); } else { // Otherwise we need to ensure the method can be reached publicly by virtual dispatch. // To avoid potential conflicts on the name of the lambda method once dispatch becomes virtual // we add the method-holder name as suffix to the lambda-method name. return new InstanceLambdaImplTarget( - rewriter - .getFactory() + appView + .dexItemFactory() .createMethod( implMethod.holder, implMethod.proto, - rewriter - .getFactory() + appView + .dexItemFactory() .createString( implMethod.name.toString() + "$" + implMethod.holder.getName()))); } @@ -412,7 +414,7 @@ // Create targets for instance method referenced directly without // lambda$ methods. It may require creation of accessors in some cases. - private Target createInstanceMethodTarget(DexType accessedFrom) { + private Target createInstanceMethodTarget(ProgramMethod accessedFrom) { assert descriptor.implHandle.type.isInvokeInstance() || descriptor.implHandle.type.isInvokeDirect(); @@ -433,18 +435,19 @@ accessorParams[0] = descriptor.getImplReceiverType(); System.arraycopy(implParams, 0, accessorParams, 1, implParams.length); DexProto accessorProto = - rewriter.getFactory().createProto(implProto.returnType, accessorParams); + appView.dexItemFactory().createProto(implProto.returnType, accessorParams); DexMethod accessorMethod = - rewriter - .getFactory() - .createMethod(accessedFrom, accessorProto, generateUniqueLambdaMethodName()); + appView + .dexItemFactory() + .createMethod( + accessedFrom.getHolderType(), accessorProto, generateUniqueLambdaMethodName()); return new ClassMethodWithAccessorTarget(accessorMethod); } // Create targets for static method referenced directly without // lambda$ methods. It may require creation of accessors in some cases. - private Target createStaticMethodTarget(DexType accessedFrom) { + private Target createStaticMethodTarget(ProgramMethod accessedFrom) { assert descriptor.implHandle.type.isInvokeStatic(); if (!descriptor.needsAccessor(accessedFrom)) { @@ -455,10 +458,10 @@ // for accessing the original static impl-method. The accessor method will be // static, package private with exactly same signature and the original method. DexMethod accessorMethod = - rewriter - .getFactory() + appView + .dexItemFactory() .createMethod( - accessedFrom, + accessedFrom.getHolderType(), descriptor.implHandle.asMethod().proto, generateUniqueLambdaMethodName()); return new ClassMethodWithAccessorTarget(accessorMethod); @@ -466,7 +469,7 @@ // Create targets for constructor referenced directly without lambda$ methods. // It may require creation of accessors in some cases. - private Target createConstructorTarget(DexType accessedFrom) { + private Target createConstructorTarget(ProgramMethod accessedFrom) { DexMethodHandle implHandle = descriptor.implHandle; assert implHandle != null; assert implHandle.type.isInvokeConstructor(); @@ -482,24 +485,25 @@ DexMethod implMethod = implHandle.asMethod(); DexType returnType = implMethod.holder; DexProto accessorProto = - rewriter.getFactory().createProto(returnType, implMethod.proto.parameters.values); + appView.dexItemFactory().createProto(returnType, implMethod.proto.parameters.values); DexMethod accessorMethod = - rewriter - .getFactory() - .createMethod(accessedFrom, accessorProto, generateUniqueLambdaMethodName()); + appView + .dexItemFactory() + .createMethod( + accessedFrom.getHolderType(), accessorProto, generateUniqueLambdaMethodName()); return new ClassMethodWithAccessorTarget(accessorMethod); } // Create targets for interface methods. - private Target createInterfaceMethodTarget(DexType accessedFrom) { + private Target createInterfaceMethodTarget(ProgramMethod accessedFrom) { assert descriptor.implHandle.type.isInvokeInterface(); assert !descriptor.needsAccessor(accessedFrom); return new NoAccessorMethodTarget(Invoke.Type.INTERFACE); } private DexString generateUniqueLambdaMethodName() { - return rewriter - .getFactory() + return appView + .dexItemFactory() .createString(LambdaRewriter.EXPECTED_LAMBDA_METHOD_PREFIX + descriptor.uniqueId); } @@ -533,16 +537,8 @@ return accessibilityBridge; } - DexClass definitionFor(DexType type) { - return rewriter.getAppInfo().app().definitionFor(type); - } - - DexProgramClass programDefinitionFor(DexType type) { - return rewriter.getAppInfo().app().programDefinitionFor(type); - } - boolean holderIsInterface() { - InternalOptions options = rewriter.getAppView().options(); + InternalOptions options = appView.options(); if (!options.isGeneratingClassFiles()) { // When generating dex the value of this flag on invokes does not matter (unused). // We cannot know if definitionFor(implMethod.holder) is null or not in that case, @@ -554,7 +550,7 @@ // implMethodHolder != null may fail, hence the assertion. assert options.cfToCfDesugar; DexMethod implMethod = descriptor.implHandle.asMethod(); - DexClass implMethodHolder = definitionFor(implMethod.holder); + DexClass implMethodHolder = appView.definitionFor(implMethod.holder); if (implMethodHolder == null) { assert options .desugaredLibraryConfiguration @@ -613,7 +609,7 @@ // For all instantiation points for which the compiler creates lambda$ // methods, it creates these methods in the same class/interface. DexMethod implMethod = descriptor.implHandle.asMethod(); - DexProgramClass implMethodHolder = definitionFor(implMethod.holder).asProgramClass(); + DexProgramClass implMethodHolder = appView.definitionFor(implMethod.holder).asProgramClass(); DexEncodedMethod replacement = implMethodHolder @@ -642,7 +638,7 @@ rewriter.originalMethodSignatures.put(callTarget, encodedMethod.method); DexEncodedMethod.setDebugInfoWithFakeThisParameter( - newMethod.getCode(), callTarget.getArity(), rewriter.getAppView()); + newMethod.getCode(), callTarget.getArity(), appView); return newMethod; }); @@ -663,11 +659,11 @@ @Override ProgramMethod ensureAccessibility(boolean allowMethodModification) { // When compiling with whole program optimization, check that we are not inplace modifying. - assert !(rewriter.getAppView().enableWholeProgramOptimizations() && allowMethodModification); + assert !(appView.enableWholeProgramOptimizations() && allowMethodModification); // For all instantiation points for which the compiler creates lambda$ // methods, it creates these methods in the same class/interface. DexMethod implMethod = descriptor.implHandle.asMethod(); - DexProgramClass implMethodHolder = definitionFor(implMethod.holder).asProgramClass(); + DexProgramClass implMethodHolder = appView.definitionFor(implMethod.holder).asProgramClass(); return allowMethodModification ? modifyLambdaImplementationMethod(implMethod, implMethodHolder) : createSyntheticAccessor(implMethod, implMethodHolder); @@ -744,7 +740,7 @@ @Override ProgramMethod ensureAccessibility(boolean allowMethodModification) { // Create a static accessor with proper accessibility. - DexProgramClass accessorClass = programDefinitionFor(callTarget.holder); + DexProgramClass accessorClass = appView.definitionForProgramType(callTarget.holder); assert accessorClass != null; // Always make the method public to provide access when r8 minification is allowed to move
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java index bfc9362..deb4579 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -11,13 +11,13 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexMethodHandle; -import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.DexTypeList; import com.android.tools.r8.graph.DexValue; import com.android.tools.r8.graph.MethodAccessFlags; +import com.android.tools.r8.graph.ProgramMethod; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.List; @@ -67,7 +67,7 @@ private LambdaDescriptor( AppInfoWithClassHierarchy appInfo, - DexType invocationContext, + ProgramMethod context, DexCallSite callSite, DexString name, DexProto erasedProto, @@ -92,8 +92,7 @@ this.captures = captures; this.interfaces.add(mainInterface); - DexEncodedMethod targetMethod = - invocationContext == null ? null : lookupTargetMethod(appInfo, invocationContext); + DexEncodedMethod targetMethod = context == null ? null : lookupTargetMethod(appInfo, context); if (targetMethod != null) { targetAccessFlags = targetMethod.accessFlags.copy(); targetHolder = targetMethod.holder(); @@ -113,17 +112,19 @@ } private DexEncodedMethod lookupTargetMethod( - AppInfoWithClassHierarchy appInfo, DexType invocationContext) { - assert invocationContext != null; + AppInfoWithClassHierarchy appInfo, ProgramMethod context) { + assert context != null; // Find the lambda's impl-method target. DexMethod method = implHandle.asMethod(); switch (implHandle.type) { case INVOKE_DIRECT: case INVOKE_INSTANCE: { DexEncodedMethod target = - appInfo.resolveMethod(getImplReceiverType(), method).getSingleTarget(); + appInfo + .resolveMethodOn(getImplReceiverType(), method, implHandle.isInterface) + .getSingleTarget(); if (target == null) { - target = appInfo.lookupDirectTarget(method, invocationContext); + target = appInfo.lookupDirectTarget(method, context); } assert target == null || (implHandle.type.isInvokeInstance() && isInstanceMethod(target)) @@ -133,20 +134,20 @@ } case INVOKE_STATIC: { - DexEncodedMethod target = appInfo.lookupStaticTarget(method, invocationContext); + DexEncodedMethod target = appInfo.lookupStaticTarget(method, context); assert target == null || target.accessFlags.isStatic(); return target; } case INVOKE_CONSTRUCTOR: { - DexEncodedMethod target = appInfo.lookupDirectTarget(method, invocationContext); + DexEncodedMethod target = appInfo.lookupDirectTarget(method, context); assert target == null || target.accessFlags.isConstructor(); return target; } case INVOKE_INTERFACE: { DexEncodedMethod target = - appInfo.resolveMethod(getImplReceiverType(), method).getSingleTarget(); + appInfo.resolveMethodOnInterface(getImplReceiverType(), method).getSingleTarget(); assert target == null || isInstanceMethod(target); return target; } @@ -187,7 +188,7 @@ } /** Checks if call site needs a accessor when referenced from `accessedFrom`. */ - boolean needsAccessor(DexType accessedFrom) { + boolean needsAccessor(ProgramMethod accessedFrom) { if (delegatesToLambdaImplMethod()) { return false; } @@ -217,8 +218,10 @@ // because the method being called must be present in method holder, // and not in one from its supertypes. boolean accessedFromSamePackage = - accessedFrom.getPackageDescriptor().equals( - implHandle.asMethod().holder.getPackageDescriptor()); + accessedFrom + .getHolderType() + .getPackageDescriptor() + .equals(implHandle.asMethod().holder.getPackageDescriptor()); return !accessedFromSamePackage; } @@ -238,7 +241,10 @@ } boolean accessedFromSamePackage = - accessedFrom.getPackageDescriptor().equals(targetHolder.getPackageDescriptor()); + accessedFrom + .getHolderType() + .getPackageDescriptor() + .equals(targetHolder.getPackageDescriptor()); assert flags.isProtected() || accessedFromSamePackage; return flags.isProtected() && !accessedFromSamePackage; } @@ -248,8 +254,8 @@ * information, or null if match failed. */ public static LambdaDescriptor tryInfer( - DexCallSite callSite, AppInfoWithClassHierarchy appInfo, DexProgramClass invocationContext) { - LambdaDescriptor descriptor = infer(callSite, appInfo, invocationContext.type); + DexCallSite callSite, AppInfoWithClassHierarchy appInfo, ProgramMethod context) { + LambdaDescriptor descriptor = infer(callSite, appInfo, context); return descriptor == MATCH_FAILED ? null : descriptor; } @@ -265,7 +271,7 @@ * information, or MATCH_FAILED if match failed. */ static LambdaDescriptor infer( - DexCallSite callSite, AppInfoWithClassHierarchy appInfo, DexType invocationContext) { + DexCallSite callSite, AppInfoWithClassHierarchy appInfo, ProgramMethod context) { if (!isLambdaMetafactoryMethod(callSite, appInfo.dexItemFactory())) { return LambdaDescriptor.MATCH_FAILED; } @@ -309,7 +315,7 @@ LambdaDescriptor match = new LambdaDescriptor( appInfo, - invocationContext, + context, callSite, funcMethodName, funcErasedSignature.value,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java index 6b41818..aa47bdc 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -4,13 +4,9 @@ package com.android.tools.r8.ir.desugar; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication.Builder; import com.android.tools.r8.graph.DexCallSite; -import com.android.tools.r8.graph.DexEncodedField; -import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; @@ -59,7 +55,7 @@ static final String EXPECTED_LAMBDA_METHOD_PREFIX = "lambda$"; private static final String LAMBDA_INSTANCE_FIELD_NAME = "INSTANCE"; - private final AppView<? extends AppInfoWithClassHierarchy> appView; + private final AppView<?> appView; final DexString instanceFieldName; @@ -76,42 +72,9 @@ // NOTE: synchronize concurrent access on `knownLambdaClasses`. private final Map<DexType, LambdaClass> knownLambdaClasses = new IdentityHashMap<>(); - // Checks if the type starts with lambda-class prefix. - public static boolean hasLambdaClassPrefix(DexType clazz) { - return clazz.getName().startsWith(LAMBDA_CLASS_NAME_PREFIX); - } - public LambdaRewriter(AppView<?> appView) { - assert appView.appInfo().hasClassHierarchy() - : "Lambda desugaring is not available without class hierarchy."; - this.appView = appView.withClassHierarchy(); - this.instanceFieldName = getFactory().createString(LAMBDA_INSTANCE_FIELD_NAME); - } - - public AppView<?> getAppView() { - return appView; - } - - public AppInfoWithClassHierarchy getAppInfo() { - return appView.appInfo(); - } - - public DexItemFactory getFactory() { - return getAppView().dexItemFactory(); - } - - public Map<DexEncodedField, Set<DexEncodedMethod>> getWritesWithContexts( - DexProgramClass synthesizedLambdaClass) { - // Record that the static fields on each lambda class are only written inside the static - // initializer of the lambdas. - Map<DexEncodedField, Set<DexEncodedMethod>> writesWithContexts = new IdentityHashMap<>(); - DexEncodedMethod clinit = synthesizedLambdaClass.getClassInitializer(); - if (clinit != null) { - for (DexEncodedField field : synthesizedLambdaClass.staticFields()) { - writesWithContexts.put(field, ImmutableSet.of(clinit)); - } - } - return writesWithContexts; + this.appView = appView; + this.instanceFieldName = appView.dexItemFactory().createString(LAMBDA_INSTANCE_FIELD_NAME); } private void synthesizeAccessibilityBridgesForLambdaClassesD8( @@ -136,9 +99,9 @@ * * <p>NOTE: this method can be called concurrently for several different methods. */ - public void desugarLambdas(DexEncodedMethod encodedMethod, IRCode code) { + public void desugarLambdas(IRCode code) { Set<Value> affectedValues = Sets.newIdentityHashSet(); - DexType currentType = encodedMethod.holder(); + ProgramMethod context = code.context(); ListIterator<BasicBlock> blocks = code.listIterator(); while (blocks.hasNext()) { BasicBlock block = blocks.next(); @@ -147,8 +110,7 @@ Instruction instruction = instructions.next(); if (instruction.isInvokeCustom()) { InvokeCustom invoke = instruction.asInvokeCustom(); - LambdaDescriptor descriptor = - inferLambdaDescriptor(invoke.getCallSite(), encodedMethod.holder()); + LambdaDescriptor descriptor = inferLambdaDescriptor(invoke.getCallSite(), context); if (descriptor == LambdaDescriptor.MATCH_FAILED) { continue; } @@ -156,9 +118,9 @@ // We have a descriptor, get the lambda class. In D8, we synthesize the lambda classes // during IR processing, and therefore we may need to create it now. LambdaClass lambdaClass = - getAppView().enableWholeProgramOptimizations() - ? getKnownLambdaClass(descriptor, currentType) - : getOrCreateLambdaClass(descriptor, currentType); + appView.enableWholeProgramOptimizations() + ? getKnownLambdaClass(descriptor, context) + : getOrCreateLambdaClass(descriptor, context); assert lambdaClass != null; // We rely on patch performing its work in a way which @@ -169,7 +131,7 @@ } } if (!affectedValues.isEmpty()) { - new TypeAnalysis(getAppView()).narrowing(affectedValues); + new TypeAnalysis(appView).narrowing(affectedValues); } assert code.isConsistentSSA(); } @@ -177,7 +139,7 @@ /** Remove lambda deserialization methods. */ public void removeLambdaDeserializationMethods(Iterable<DexProgramClass> classes) { for (DexProgramClass clazz : classes) { - clazz.removeMethod(getFactory().deserializeLambdaMethod); + clazz.removeMethod(appView.dexItemFactory().deserializeLambdaMethod); } } @@ -189,7 +151,7 @@ knownLambdaClasses.values(), converter, executorService); for (LambdaClass lambdaClass : knownLambdaClasses.values()) { DexProgramClass synthesizedClass = lambdaClass.getOrCreateLambdaClass(); - getAppInfo().addSynthesizedClass(synthesizedClass); + appView.appInfo().addSynthesizedClass(synthesizedClass); builder.addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get()); } optimizeSynthesizedClasses(converter, executorService); @@ -204,17 +166,11 @@ executorService); } - public Set<DexCallSite> getDesugaredCallSites() { - synchronized (knownCallSites) { - return knownCallSites.keySet(); - } - } - // Matches invoke-custom instruction operands to infer lambda descriptor // corresponding to this lambda invocation point. // // Returns the lambda descriptor or `MATCH_FAILED`. - private LambdaDescriptor inferLambdaDescriptor(DexCallSite callSite, DexType invocationContext) { + private LambdaDescriptor inferLambdaDescriptor(DexCallSite callSite, ProgramMethod context) { // We check the map before and after inferring lambda descriptor to minimize time // spent in synchronized block. As a result we may throw away calculated descriptor // in rare case when another thread has same call site processed concurrently, @@ -225,17 +181,18 @@ : putIfAbsent( knownCallSites, callSite, - LambdaDescriptor.infer(callSite, getAppInfo(), invocationContext)); + LambdaDescriptor.infer(callSite, appView.appInfoForDesugaring(), context)); } private boolean isInMainDexList(DexType type) { - return getAppInfo().isInMainDexList(type); + return appView.appInfo().isInMainDexList(type); } // Returns a lambda class corresponding to the lambda descriptor and context, // creates the class if it does not yet exist. - public LambdaClass getOrCreateLambdaClass(LambdaDescriptor descriptor, DexType accessedFrom) { - DexType lambdaClassType = LambdaClass.createLambdaClassType(this, accessedFrom, descriptor); + public LambdaClass getOrCreateLambdaClass( + LambdaDescriptor descriptor, ProgramMethod accessedFrom) { + DexType lambdaClassType = LambdaClass.createLambdaClassType(appView, accessedFrom, descriptor); // We check the map twice to to minimize time spent in synchronized block. LambdaClass lambdaClass = getKnown(knownLambdaClasses, lambdaClassType); if (lambdaClass == null) { @@ -243,50 +200,50 @@ putIfAbsent( knownLambdaClasses, lambdaClassType, - new LambdaClass(this, accessedFrom, lambdaClassType, descriptor)); - if (getAppView().options().isDesugaredLibraryCompilation()) { + new LambdaClass(appView, this, accessedFrom, lambdaClassType, descriptor)); + if (appView.options().isDesugaredLibraryCompilation()) { DexType rewrittenType = - getAppView().rewritePrefix.rewrittenType(accessedFrom, getAppView()); + appView.rewritePrefix.rewrittenType(accessedFrom.getHolderType(), appView); if (rewrittenType == null) { rewrittenType = - getAppView() + appView .options() .desugaredLibraryConfiguration .getEmulateLibraryInterface() - .get(accessedFrom); + .get(accessedFrom.getHolderType()); } if (rewrittenType != null) { addRewritingPrefix(accessedFrom, rewrittenType, lambdaClassType); } } } - lambdaClass.addSynthesizedFrom(getAppView().definitionFor(accessedFrom).asProgramClass()); - if (isInMainDexList(accessedFrom)) { + lambdaClass.addSynthesizedFrom(accessedFrom.getHolder()); + if (isInMainDexList(accessedFrom.getHolderType())) { lambdaClass.addToMainDexList.set(true); } return lambdaClass; } - private LambdaClass getKnownLambdaClass(LambdaDescriptor descriptor, DexType accessedFrom) { - DexType lambdaClassType = LambdaClass.createLambdaClassType(this, accessedFrom, descriptor); + private LambdaClass getKnownLambdaClass(LambdaDescriptor descriptor, ProgramMethod accessedFrom) { + DexType lambdaClassType = LambdaClass.createLambdaClassType(appView, accessedFrom, descriptor); return getKnown(knownLambdaClasses, lambdaClassType); } - private void addRewritingPrefix(DexType type, DexType rewritten, DexType lambdaClassType) { + private void addRewritingPrefix( + ProgramMethod context, DexType rewritten, DexType lambdaClassType) { String javaName = lambdaClassType.toString(); - String typeString = type.toString(); + String typeString = context.getHolderType().toString(); String actualPrefix = typeString.substring(0, typeString.lastIndexOf('.')); String rewrittenString = rewritten.toString(); String actualRewrittenPrefix = rewrittenString.substring(0, rewrittenString.lastIndexOf('.')); assert javaName.startsWith(actualPrefix); - getAppView() - .rewritePrefix - .rewriteType( - lambdaClassType, - getFactory() - .createType( - DescriptorUtils.javaTypeToDescriptor( - actualRewrittenPrefix + javaName.substring(actualPrefix.length())))); + appView.rewritePrefix.rewriteType( + lambdaClassType, + appView + .dexItemFactory() + .createType( + DescriptorUtils.javaTypeToDescriptor( + actualRewrittenPrefix + javaName.substring(actualPrefix.length())))); } private static <K, V> V getKnown(Map<K, V> map, K key) { @@ -326,7 +283,7 @@ // The out value might be empty in case it was optimized out. lambdaInstanceValue = code.createValue( - TypeElement.fromDexType(lambdaClass.type, Nullability.maybeNull(), getAppView())); + TypeElement.fromDexType(lambdaClass.type, Nullability.maybeNull(), appView)); } else { affectedValues.add(lambdaInstanceValue); } @@ -379,7 +336,7 @@ BasicBlock currentBlock = newInstance.getBlock(); BasicBlock nextBlock = instructions.split(code, blocks); assert !instructions.hasNext(); - nextBlock.copyCatchHandlers(code, blocks, currentBlock, getAppView().options()); + nextBlock.copyCatchHandlers(code, blocks, currentBlock, appView.options()); } public Map<DexType, LambdaClass> getKnownLambdaClasses() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaSynthesizedCode.java index 7e50b88..5643288 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaSynthesizedCode.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaSynthesizedCode.java
@@ -21,7 +21,7 @@ } final DexItemFactory dexItemFactory() { - return lambda.rewriter.getFactory(); + return lambda.appView.dexItemFactory(); } final LambdaDescriptor descriptor() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java index 7677cee..fc12713 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java
@@ -40,7 +40,7 @@ } final DexItemFactory factory() { - return lambda.rewriter.getFactory(); + return lambda.appView.dexItemFactory(); } final int enforceParameterType(int register, DexType paramType, DexType enforcedType) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java index 8d1124b..8912aeb 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
@@ -4,7 +4,6 @@ package com.android.tools.r8.ir.optimize; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; @@ -85,7 +84,7 @@ if (mode != Mode.COLLECT) { return; } - DexEncodedMethod context = code.method(); + ProgramMethod context = code.context(); for (Instruction instruction : code.instructions()) { if (!instruction.isInvokeMethod() && !instruction.isInvokeCustom()) { continue; @@ -95,26 +94,28 @@ if (invoke.isInvokeMethodWithDynamicDispatch()) { DexMethod invokedMethod = invoke.getInvokedMethod(); ResolutionResult resolutionResult = - appView.appInfo().resolveMethod(invokedMethod.holder, invokedMethod); + appView.appInfo().resolveMethod(invokedMethod, invoke.isInvokeInterface()); // For virtual and interface calls, proceed on valid results only (since it's enforced). - if (!resolutionResult.isVirtualTarget()) { + if (!resolutionResult.isSingleResolution() || !resolutionResult.isVirtualTarget()) { continue; } // If the resolution ended up with a single target, check if it is a library override. // And if so, bail out early (to avoid expensive target lookup). - if (resolutionResult.isSingleResolution() - && isLibraryMethodOrLibraryMethodOverride(resolutionResult.getSingleTarget())) { + ProgramMethod resolutionTarget = + resolutionResult.asSingleResolution().getResolutionPair().asProgramMethod(); + if (resolutionTarget == null + || isLibraryMethodOrLibraryMethodOverride(resolutionTarget)) { continue; } } - Collection<DexEncodedMethod> targets = invoke.lookupTargets(appView, context.holder()); + ProgramMethodSet targets = invoke.lookupProgramDispatchTargets(appView, context); assert invoke.isInvokeMethodWithDynamicDispatch() // For other invocation types, the size of targets should be at most one. || targets == null || targets.size() <= 1; if (targets == null || targets.isEmpty() || hasLibraryOverrides(targets)) { continue; } - for (DexEncodedMethod target : targets) { + for (ProgramMethod target : targets) { recordArgumentsIfNecessary(target, invoke.inValues()); } } @@ -132,7 +133,6 @@ appView .appInfo() .resolveMethod( - bootstrapMethod.asMethod().holder, bootstrapMethod.asMethod(), bootstrapMethod.isInterface) .asSingleResolution(); @@ -147,8 +147,8 @@ // TODO(b/140204899): Instead of reprocessing here, pass stopping criteria to lookup? // If any of target method is a library method override, bail out entirely/early. - private boolean hasLibraryOverrides(Collection<DexEncodedMethod> targets) { - for (DexEncodedMethod target : targets) { + private boolean hasLibraryOverrides(ProgramMethodSet targets) { + for (ProgramMethod target : targets) { if (isLibraryMethodOrLibraryMethodOverride(target)) { return true; } @@ -156,54 +156,42 @@ return false; } - private boolean isLibraryMethodOrLibraryMethodOverride(DexEncodedMethod target) { - // Not a program method. - if (!target.isProgramMethod(appView)) { - return true; - } + private boolean isLibraryMethodOrLibraryMethodOverride(ProgramMethod target) { // If the method overrides a library method, it is unsure how the method would be invoked by // that library. - if (target.isLibraryMethodOverride().isTrue()) { - return true; - } - return false; + return target.getDefinition().isLibraryMethodOverride().isTrue(); } // Record arguments for the given method if necessary. // At the same time, if it decides to bail out, make the corresponding info immutable so that we // can avoid recording arguments for the same method accidentally. - private void recordArgumentsIfNecessary(DexEncodedMethod target, List<Value> inValues) { - assert !target.isObsolete(); - if (appView.appInfo().neverReprocess.contains(target.method)) { + private void recordArgumentsIfNecessary(ProgramMethod target, List<Value> inValues) { + assert !target.getDefinition().isObsolete(); + if (appView.appInfo().neverReprocess.contains(target.getReference())) { return; } - if (target.getCallSiteOptimizationInfo().isTop()) { + if (target.getDefinition().getCallSiteOptimizationInfo().isTop()) { return; } - target.joinCallSiteOptimizationInfo( - computeCallSiteOptimizationInfoFromArguments(target, inValues), appView); + target + .getDefinition() + .joinCallSiteOptimizationInfo( + computeCallSiteOptimizationInfoFromArguments(target, inValues), appView); } private CallSiteOptimizationInfo computeCallSiteOptimizationInfoFromArguments( - DexEncodedMethod target, List<Value> inValues) { + ProgramMethod target, List<Value> inValues) { // No method body or no argument at all. - if (target.shouldNotHaveCode() || inValues.size() == 0) { + if (target.getDefinition().shouldNotHaveCode() || inValues.size() == 0) { return CallSiteOptimizationInfo.TOP; } // If pinned, that method could be invoked via reflection. - if (appView.appInfo().isPinned(target.method)) { - return CallSiteOptimizationInfo.TOP; - } - // Not a program method. - if (!target.isProgramMethod(appView)) { - // But, should not be reachable, since we already bail out. - assert false - : "Trying to compute call site optimization info for " + target.toSourceString(); + if (appView.appInfo().isPinned(target.getReference())) { return CallSiteOptimizationInfo.TOP; } // If the method overrides a library method, it is unsure how the method would be invoked by // that library. - if (target.isLibraryMethodOverride().isTrue()) { + if (target.getDefinition().isLibraryMethodOverride().isTrue()) { // But, should not be reachable, since we already bail out. assert false : "Trying to compute call site optimization info for " + target.toSourceString(); @@ -212,8 +200,8 @@ // If the program already has illegal accesses, method resolution results will reflect that too. // We should avoid recording arguments in that case. E.g., b/139823850: static methods can be a // result of virtual call targets, if that's the only method that matches name and signature. - int argumentOffset = target.isStatic() ? 0 : 1; - if (inValues.size() != argumentOffset + target.method.getArity()) { + int argumentOffset = target.getDefinition().isStatic() ? 0 : 1; + if (inValues.size() != argumentOffset + target.getReference().getArity()) { return CallSiteOptimizationInfo.BOTTOM; } return ConcreteCallSiteOptimizationInfo.fromArguments(appView, target, inValues);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java index ce853a2..a7a24cc 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -12,7 +12,6 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; -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; @@ -29,6 +28,8 @@ import com.android.tools.r8.graph.DexValue.DexValueNull; import com.android.tools.r8.graph.DexValue.DexValueShort; import com.android.tools.r8.graph.DexValue.DexValueString; +import com.android.tools.r8.graph.FieldResolutionResult; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ValueMayDependOnEnvironmentAnalysis; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.code.ArrayPut; @@ -53,7 +54,6 @@ import com.android.tools.r8.utils.IteratorUtils; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import java.util.Collection; import java.util.IdentityHashMap; import java.util.Map; import java.util.Set; @@ -123,18 +123,17 @@ this.dexItemFactory = appView.dexItemFactory(); } - public ClassInitializerDefaultsResult optimize( - DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) { - if (appView.options().debug || method.getOptimizationInfo().isReachabilitySensitive()) { + public ClassInitializerDefaultsResult optimize(IRCode code, OptimizationFeedback feedback) { + if (appView.options().debug) { return ClassInitializerDefaultsResult.empty(); } - if (!method.isClassInitializer()) { + ProgramMethod context = code.context(); + if (context.getDefinition().getOptimizationInfo().isReachabilitySensitive()) { return ClassInitializerDefaultsResult.empty(); } - DexClass clazz = appView.definitionFor(method.holder()); - if (clazz == null) { + if (!context.getDefinition().isClassInitializer()) { return ClassInitializerDefaultsResult.empty(); } @@ -142,8 +141,9 @@ // a static put on a field on this class with a value that can be hoisted to // the field initial value. Set<StaticPut> unnecessaryStaticPuts = Sets.newIdentityHashSet(); - Collection<StaticPut> finalFieldPuts = - findFinalFieldPutsWhileCollectingUnnecessaryStaticPuts(code, clazz, unnecessaryStaticPuts); + Map<DexEncodedField, StaticPut> finalFieldPuts = + findFinalFieldPutsWhileCollectingUnnecessaryStaticPuts( + code, context, unnecessaryStaticPuts); // Return eagerly if there is nothing to optimize. if (finalFieldPuts.isEmpty()) { @@ -154,43 +154,43 @@ Map<DexEncodedField, DexValue> fieldsWithStaticValues = new IdentityHashMap<>(); // Set initial values for static fields from the definitive static put instructions collected. - for (StaticPut put : finalFieldPuts) { - DexEncodedField field = appView.appInfo().resolveField(put.getField()); - DexType fieldType = field.field.type; - Value value = put.value(); - if (unnecessaryStaticPuts.contains(put)) { - if (fieldType == dexItemFactory.stringType) { - fieldsWithStaticValues.put(field, getDexStringValue(value, method.holder())); - } else if (fieldType.isClassType() || fieldType.isArrayType()) { - if (value.isZero()) { - fieldsWithStaticValues.put(field, DexValueNull.NULL); - } else { - throw new Unreachable("Unexpected default value for field type " + fieldType + "."); + finalFieldPuts.forEach( + (field, put) -> { + DexType fieldType = field.field.type; + Value value = put.value(); + if (unnecessaryStaticPuts.contains(put)) { + if (fieldType == dexItemFactory.stringType) { + fieldsWithStaticValues.put(field, getDexStringValue(value, context.getHolderType())); + } else if (fieldType.isClassType() || fieldType.isArrayType()) { + if (value.isZero()) { + fieldsWithStaticValues.put(field, DexValueNull.NULL); + } else { + throw new Unreachable("Unexpected default value for field type " + fieldType + "."); + } + } else { + ConstNumber cnst = value.getConstInstruction().asConstNumber(); + if (fieldType == dexItemFactory.booleanType) { + fieldsWithStaticValues.put(field, DexValueBoolean.create(cnst.getBooleanValue())); + } else if (fieldType == dexItemFactory.byteType) { + fieldsWithStaticValues.put(field, DexValueByte.create((byte) cnst.getIntValue())); + } else if (fieldType == dexItemFactory.shortType) { + fieldsWithStaticValues.put(field, DexValueShort.create((short) cnst.getIntValue())); + } else if (fieldType == dexItemFactory.intType) { + fieldsWithStaticValues.put(field, DexValueInt.create(cnst.getIntValue())); + } else if (fieldType == dexItemFactory.longType) { + fieldsWithStaticValues.put(field, DexValueLong.create(cnst.getLongValue())); + } else if (fieldType == dexItemFactory.floatType) { + fieldsWithStaticValues.put(field, DexValueFloat.create(cnst.getFloatValue())); + } else if (fieldType == dexItemFactory.doubleType) { + fieldsWithStaticValues.put(field, DexValueDouble.create(cnst.getDoubleValue())); + } else if (fieldType == dexItemFactory.charType) { + fieldsWithStaticValues.put(field, DexValueChar.create((char) cnst.getIntValue())); + } else { + throw new Unreachable("Unexpected field type " + fieldType + "."); + } + } } - } else { - ConstNumber cnst = value.getConstInstruction().asConstNumber(); - if (fieldType == dexItemFactory.booleanType) { - fieldsWithStaticValues.put(field, DexValueBoolean.create(cnst.getBooleanValue())); - } else if (fieldType == dexItemFactory.byteType) { - fieldsWithStaticValues.put(field, DexValueByte.create((byte) cnst.getIntValue())); - } else if (fieldType == dexItemFactory.shortType) { - fieldsWithStaticValues.put(field, DexValueShort.create((short) cnst.getIntValue())); - } else if (fieldType == dexItemFactory.intType) { - fieldsWithStaticValues.put(field, DexValueInt.create(cnst.getIntValue())); - } else if (fieldType == dexItemFactory.longType) { - fieldsWithStaticValues.put(field, DexValueLong.create(cnst.getLongValue())); - } else if (fieldType == dexItemFactory.floatType) { - fieldsWithStaticValues.put(field, DexValueFloat.create(cnst.getFloatValue())); - } else if (fieldType == dexItemFactory.doubleType) { - fieldsWithStaticValues.put(field, DexValueDouble.create(cnst.getDoubleValue())); - } else if (fieldType == dexItemFactory.charType) { - fieldsWithStaticValues.put(field, DexValueChar.create((char) cnst.getIntValue())); - } else { - throw new Unreachable("Unexpected field type " + fieldType + "."); - } - } - } - } + }); if (!unnecessaryStaticPuts.isEmpty()) { // Remove the static put instructions now replaced by static field initial values. @@ -239,10 +239,11 @@ // First collect all the candidate fields that are *potentially* no longer being written to. Set<DexField> candidates = - finalFieldPuts.stream() + finalFieldPuts.values().stream() .filter(unnecessaryStaticPuts::contains) .map(FieldInstruction::getField) .map(appInfoWithLiveness::resolveField) + .map(FieldResolutionResult::getResolvedField) .filter(appInfoWithLiveness::isStaticFieldWrittenOnlyInEnclosingStaticInitializer) .map(field -> field.field) .collect(Collectors.toSet()); @@ -252,7 +253,8 @@ if (instruction.isStaticPut()) { StaticPut staticPutInstruction = instruction.asStaticPut(); DexField field = staticPutInstruction.getField(); - DexEncodedField encodedField = appInfoWithLiveness.resolveField(field); + DexEncodedField encodedField = + appInfoWithLiveness.resolveField(field).getResolvedField(); if (encodedField != null) { candidates.remove(encodedField.field); } @@ -357,13 +359,13 @@ return null; } - private Collection<StaticPut> findFinalFieldPutsWhileCollectingUnnecessaryStaticPuts( - IRCode code, DexClass clazz, Set<StaticPut> unnecessaryStaticPuts) { + private Map<DexEncodedField, StaticPut> findFinalFieldPutsWhileCollectingUnnecessaryStaticPuts( + IRCode code, ProgramMethod context, Set<StaticPut> unnecessaryStaticPuts) { ValueMayDependOnEnvironmentAnalysis environmentAnalysis = new ValueMayDependOnEnvironmentAnalysis(appView, code); - Map<DexField, StaticPut> finalFieldPuts = Maps.newIdentityHashMap(); + Map<DexEncodedField, StaticPut> finalFieldPuts = Maps.newIdentityHashMap(); Map<DexField, Set<StaticPut>> isWrittenBefore = Maps.newIdentityHashMap(); - Set<DexField> isReadBefore = Sets.newIdentityHashSet(); + Set<DexEncodedField> isReadBefore = Sets.newIdentityHashSet(); final int color = code.reserveMarkingColor(); try { BasicBlock block = code.entryBlock(); @@ -374,29 +376,30 @@ // Array stores do not impact our ability to move constants into the class definition, // as long as the instructions do not throw. ArrayPut arrayPut = instruction.asArrayPut(); - if (arrayPut.instructionInstanceCanThrow(appView, clazz.type).isThrowing()) { + if (arrayPut.instructionInstanceCanThrow(appView, context).isThrowing()) { return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore); } } else if (instruction.isStaticGet()) { StaticGet get = instruction.asStaticGet(); - DexEncodedField field = appView.appInfo().resolveField(get.getField()); - if (field != null && field.holder() == clazz.type) { - isReadBefore.add(field.field); - } else if (instruction.instructionMayHaveSideEffects(appView, clazz.type)) { + DexEncodedField field = context.getHolder().lookupField(get.getField()); + if (field != null) { + isReadBefore.add(field); + } else { // Reading another field is only OK if the read does not have side-effects. return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore); } } else if (instruction.isStaticPut()) { StaticPut put = instruction.asStaticPut(); - if (put.getField().holder != clazz.type) { + if (put.getField().holder != context.getHolderType()) { // Can cause clinit on another class which can read uninitialized static fields // of this class. return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore); } - DexField field = put.getField(); + DexField fieldReference = put.getField(); + DexEncodedField field = context.getHolder().lookupField(fieldReference); Value value = put.value(); TypeElement valueType = value.getType(); - if (clazz.definesStaticField(field)) { + if (field != null) { if (isReadBefore.contains(field)) { // Promoting this put to a class constant would cause a previous static-get // instruction to read a different value. @@ -406,37 +409,37 @@ continue; } if (value.isConstant()) { - if (field.type.isReferenceType() && value.isZero()) { + if (fieldReference.type.isReferenceType() && value.isZero()) { finalFieldPuts.put(field, put); unnecessaryStaticPuts.add(put); // If this field has been written before, those static-put's up to this point are // redundant. We should remove them all together; otherwise, remaining static-put // that is not constant can change the program semantics. See b/138912149. - if (isWrittenBefore.containsKey(field)) { - unnecessaryStaticPuts.addAll(isWrittenBefore.get(field)); - isWrittenBefore.remove(field); + if (isWrittenBefore.containsKey(fieldReference)) { + unnecessaryStaticPuts.addAll(isWrittenBefore.get(fieldReference)); + isWrittenBefore.remove(fieldReference); } continue; - } else if (field.type.isPrimitiveType() - || field.type == dexItemFactory.stringType) { + } else if (fieldReference.type.isPrimitiveType() + || fieldReference.type == dexItemFactory.stringType) { finalFieldPuts.put(field, put); unnecessaryStaticPuts.add(put); - if (isWrittenBefore.containsKey(field)) { - unnecessaryStaticPuts.addAll(isWrittenBefore.get(field)); - isWrittenBefore.remove(field); + if (isWrittenBefore.containsKey(fieldReference)) { + unnecessaryStaticPuts.addAll(isWrittenBefore.get(fieldReference)); + isWrittenBefore.remove(fieldReference); } continue; } // Still constant, but not able to represent it as static encoded values, e.g., // const-class, const-method-handle, etc. This static-put can be redundant if the // field is rewritten with another constant. Will fall through and track static-put. - } else if (isClassNameConstantOf(clazz, put)) { + } else if (isClassNameConstantOf(context.getHolder(), put)) { // Collect put of class name constant as a potential default value. finalFieldPuts.put(field, put); unnecessaryStaticPuts.add(put); - if (isWrittenBefore.containsKey(field)) { - unnecessaryStaticPuts.addAll(isWrittenBefore.get(field)); - isWrittenBefore.remove(field); + if (isWrittenBefore.containsKey(fieldReference)) { + unnecessaryStaticPuts.addAll(isWrittenBefore.get(fieldReference)); + isWrittenBefore.remove(fieldReference); } continue; } else if (valueType.isReferenceType() && valueType.isDefinitelyNotNull()) { @@ -448,19 +451,19 @@ // However, if static-put is still remaining in `isWrittenBefore`, that indicates // the previous candidate as final field put is no longer valid. isWrittenBefore - .computeIfAbsent(field, ignore -> Sets.newIdentityHashSet()) + .computeIfAbsent(fieldReference, ignore -> Sets.newIdentityHashSet()) .add(put); } else { // Writing another field is not OK. return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore); } - } else if (instruction.instructionMayHaveSideEffects(appView, clazz.type)) { + } else if (instruction.instructionMayHaveSideEffects(appView, context)) { // Some other instruction that has side-effects. Stop here. return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore); } else { // TODO(b/120138731): This check should be removed when the Class.get*Name() // optimizations become enabled. - if (isClassNameConstantOf(clazz, instruction)) { + if (isClassNameConstantOf(context.getHolder(), instruction)) { // OK, this does not read one of the fields in the enclosing class. continue; } @@ -489,8 +492,8 @@ return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore); } - private Collection<StaticPut> validateFinalFieldPuts( - Map<DexField, StaticPut> finalFieldPuts, + private Map<DexEncodedField, StaticPut> validateFinalFieldPuts( + Map<DexEncodedField, StaticPut> finalFieldPuts, Map<DexField, Set<StaticPut>> isWrittenBefore) { // If a field is rewritten again with other values that we can't represent as static encoded // values, that would be recorded at `isWrittenBefore`, which is used to collect and remove @@ -512,7 +515,7 @@ // values, leaving it can cause incorrect optimizations. Thus, we invalidate candidates of // final field puts at all. isWrittenBefore.keySet().forEach(finalFieldPuts::remove); - return finalFieldPuts.values(); + return finalFieldPuts; } // Check if the static put is a constant derived from the class holding the method.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java index 3dbe05d..29a0c32 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -24,6 +24,7 @@ import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.equivalence.BasicBlockBehavioralSubsumption; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -312,7 +313,7 @@ boolean canDetachValueIsNullTarget = true; for (Instruction i : valueIsNullTarget.instructionsBefore(throwInstruction)) { - if (!i.isBlockLocalInstructionWithoutSideEffects(appView, code.method().holder())) { + if (!i.isBlockLocalInstructionWithoutSideEffects(appView, code.context())) { canDetachValueIsNullTarget = false; break; } @@ -1133,7 +1134,7 @@ BasicBlock defaultTarget = theSwitch.fallthroughBlock(); SwitchCaseEliminator eliminator = null; BasicBlockBehavioralSubsumption behavioralSubsumption = - new BasicBlockBehavioralSubsumption(appView, code.method().holder()); + new BasicBlockBehavioralSubsumption(appView, code.context()); // Compute the set of switch cases that can be removed. int alwaysHitCase = -1; @@ -1258,7 +1259,7 @@ } // Check if the invoked method is known to return one of its arguments. - DexEncodedMethod target = invoke.lookupSingleTarget(appView, code.method().holder()); + DexEncodedMethod target = invoke.lookupSingleTarget(appView, code.context()); if (target != null && target.getOptimizationInfo().returnsArgument()) { int argumentIndex = target.getOptimizationInfo().getReturnedArgument(); // Replace the out value of the invoke with the argument and ignore the out value. @@ -1380,7 +1381,7 @@ // If the cast type is not accessible in the current context, we should not remove the cast // in order to preserve IllegalAccessError. Note that JVM and ART behave differently: see // {@link com.android.tools.r8.ir.optimize.checkcast.IllegalAccessErrorTest}. - if (!isTypeVisibleFromContext(appView, code.method().holder(), castType)) { + if (!isTypeVisibleFromContext(appView, code.context(), castType)) { return RemoveCheckCastInstructionIfTrivialResult.NO_REMOVALS; } @@ -1437,7 +1438,7 @@ InstanceOf instanceOf, InstructionListIterator it, IRCode code) { // If the instance-of type is not accessible in the current context, we should not remove the // instance-of instruction in order to preserve IllegalAccessError. - if (!isTypeVisibleFromContext(appView, code.method().holder(), instanceOf.type())) { + if (!isTypeVisibleFromContext(appView, code.context(), instanceOf.type())) { return false; } @@ -2505,7 +2506,7 @@ } } } else { - DexType context = code.method().holder(); + ProgramMethod context = code.context(); AbstractValue abstractValue = lhs.getAbstractValue(appView, context); if (abstractValue.isSingleConstClassValue()) { AbstractValue otherAbstractValue = rhs.getAbstractValue(appView, context); @@ -2822,7 +2823,7 @@ InvokeMethod invoke = insn.asInvokeMethod(); DexEncodedMethod singleTarget = - invoke.lookupSingleTarget(appView.withLiveness(), code.method().holder()); + invoke.lookupSingleTarget(appView.withLiveness(), code.context()); if (singleTarget == null || !singleTarget.getOptimizationInfo().neverReturnsNormally()) { continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java index 691de34..36fba35 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
@@ -11,8 +11,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.analysis.value.SingleFieldValue; import com.android.tools.r8.ir.code.BasicBlock; @@ -87,8 +86,7 @@ } public void canonicalize(AppView<?> appView, IRCode code) { - DexEncodedMethod method = code.method(); - DexType context = method.holder(); + ProgramMethod context = code.context(); Object2ObjectLinkedOpenCustomHashMap<Instruction, List<Value>> valuesDefinedByConstant = new Object2ObjectLinkedOpenCustomHashMap<>( new Strategy<Instruction>() { @@ -149,7 +147,8 @@ continue; } SingleFieldValue singleFieldValue = abstractValue.asSingleFieldValue(); - if (method.isClassInitializer() && method.holder() == singleFieldValue.getField().holder) { + if (context.getDefinition().isClassInitializer() + && context.getHolderType() == singleFieldValue.getField().holder) { // Avoid that canonicalization inserts a read before the unique write in the class // initializer, as that would change the program behavior. continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java index e0066a7..4b8ee00 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -9,7 +9,6 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.Code; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexField; @@ -328,11 +327,7 @@ ClassInitializationAnalysis classInitializationAnalysis, WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) { InlineAction action = new InlineAction(singleTarget, invoke, reason); - if (isTargetClassInitialized( - invoke, - method.getDefinition(), - singleTarget.getDefinition(), - classInitializationAnalysis)) { + if (isTargetClassInitialized(invoke, method, singleTarget, classInitializationAnalysis)) { return action; } if (appView.canUseInitClass() @@ -346,8 +341,8 @@ private boolean isTargetClassInitialized( InvokeStatic invoke, - DexEncodedMethod method, - DexEncodedMethod target, + ProgramMethod context, + ProgramMethod target, ClassInitializationAnalysis classInitializationAnalysis) { // Only proceed with inlining a static invoke if: // - the holder for the target is a subtype of the holder for the method, @@ -356,28 +351,24 @@ // - the current method has already triggered the holder for the target method to be // initialized, or // - there is no non-trivial class initializer. - DexType targetHolder = target.holder(); - if (appView.appInfo().isSubtype(method.holder(), targetHolder)) { + if (appView.appInfo().isSubtype(context.getHolderType(), target.getHolderType())) { return true; } - DexClass clazz = appView.definitionFor(targetHolder); - assert clazz != null; - if (target.getOptimizationInfo().triggersClassInitBeforeAnySideEffect()) { + if (target.getDefinition().getOptimizationInfo().triggersClassInitBeforeAnySideEffect()) { return true; } - if (!method.isStatic()) { + if (!context.getDefinition().isStatic()) { boolean targetIsGuaranteedToBeInitialized = appView.withInitializedClassesInInstanceMethods( analysis -> - analysis.isClassDefinitelyLoadedInInstanceMethodsOn( - target.holder(), method.holder()), + analysis.isClassDefinitelyLoadedInInstanceMethod(target.getHolder(), context), false); if (targetIsGuaranteedToBeInitialized) { return true; } } if (classInitializationAnalysis.isClassDefinitelyLoadedBeforeInstruction( - target.holder(), invoke)) { + target.getHolderType(), invoke)) { return true; } // Check for class initializer side effects when loading this class, as inlining might remove @@ -387,11 +378,11 @@ // // For simplicity, we are conservative and consider all interfaces, not only the ones with // default methods. - if (!clazz.classInitializationMayHaveSideEffects(appView)) { + if (!target.getHolder().classInitializationMayHaveSideEffects(appView)) { return true; } - if (appView.rootSet().bypassClinitForInlining.contains(target.method)) { + if (appView.rootSet().bypassClinitForInlining.contains(target.getReference())) { return true; } @@ -488,7 +479,7 @@ // Final fields may not be initialized outside of a constructor in the enclosing class. InstancePut instancePut = instruction.asInstancePut(); DexField field = instancePut.getField(); - DexEncodedField target = appView.appInfo().lookupInstanceTarget(field.holder, field); + DexEncodedField target = appView.appInfo().lookupInstanceTarget(field); if (target == null || target.accessFlags.isFinal()) { whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToFinalFieldAssignment( instancePut);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java index 0366798..8117d6c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -7,8 +7,8 @@ import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -52,8 +52,9 @@ this.appView = appView; } - public void devirtualizeInvokeInterface(IRCode code, DexProgramClass context) { + public void devirtualizeInvokeInterface(IRCode code) { Set<Value> affectedValues = Sets.newIdentityHashSet(); + ProgramMethod context = code.context(); Map<InvokeInterface, InvokeVirtual> devirtualizedCall = new IdentityHashMap<>(); DominatorTree dominatorTree = new DominatorTree(code); Map<Value, Map<DexType, Value>> castedReceiverCache = new IdentityHashMap<>(); @@ -118,14 +119,14 @@ if (appView.options().testing.enableInvokeSuperToInvokeVirtualRewriting) { if (current.isInvokeSuper()) { InvokeSuper invoke = current.asInvokeSuper(); - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context.type); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context); if (singleTarget != null) { DexClass holder = appView.definitionForHolder(singleTarget); assert holder != null; DexMethod invokedMethod = invoke.getInvokedMethod(); DexEncodedMethod newSingleTarget = InvokeVirtual.lookupSingleTarget( - appView, context.type, invokedMethod, invoke.getReceiver()); + appView, context, invoke.getReceiver(), invokedMethod); if (newSingleTarget == singleTarget) { it.replaceCurrentInstruction( new InvokeVirtual(invokedMethod, invoke.outValue(), invoke.arguments())); @@ -139,7 +140,7 @@ InvokeVirtual invoke = current.asInvokeVirtual(); DexMethod invokedMethod = invoke.getInvokedMethod(); DexMethod reboundTarget = - rebindVirtualInvokeToMostSpecific(invokedMethod, invoke.getReceiver(), context.type); + rebindVirtualInvokeToMostSpecific(invokedMethod, invoke.getReceiver(), context); if (reboundTarget != invokedMethod) { it.replaceCurrentInstruction( new InvokeVirtual(reboundTarget, invoke.outValue(), invoke.arguments())); @@ -151,7 +152,7 @@ continue; } InvokeInterface invoke = current.asInvokeInterface(); - DexEncodedMethod target = invoke.lookupSingleTarget(appView, context.type); + DexEncodedMethod target = invoke.lookupSingleTarget(appView, context); if (target == null) { continue; } @@ -163,7 +164,7 @@ } // Due to the potential downcast below, make sure the new target holder is visible. ConstraintWithTarget visibility = - ConstraintWithTarget.classIsVisible(context.type, holderType, appView); + ConstraintWithTarget.classIsVisible(context.getHolder(), holderType, appView); if (visibility == ConstraintWithTarget.NEVER) { continue; } @@ -279,7 +280,7 @@ * entirely. Without this rewriting, we would have to keep A.foo() because the method is targeted. */ private DexMethod rebindVirtualInvokeToMostSpecific( - DexMethod target, Value receiver, DexType context) { + DexMethod target, Value receiver, ProgramMethod context) { if (!receiver.getType().isClassType()) { return target; } @@ -296,7 +297,8 @@ // Virtual invoke is already as specific as it can get. return target; } - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(receiverType, target); + ResolutionResult resolutionResult = + appView.appInfo().resolveMethodOnClass(target, receiverType); DexEncodedMethod newTarget = resolutionResult.isVirtualTarget() ? resolutionResult.getSingleTarget() : null; if (newTarget == null || newTarget.method == target) { @@ -318,10 +320,11 @@ return target.isNonPrivateVirtualMethod() && appView.isInterface(target.holder()).isFalse(); } - private boolean hasAccessToInvokeTargetFromContext(DexEncodedMethod target, DexType context) { + private boolean hasAccessToInvokeTargetFromContext( + DexEncodedMethod target, ProgramMethod context) { assert !target.accessFlags.isPrivate(); DexType holder = target.holder(); - if (holder == context) { + if (holder == context.getHolderType()) { // It is always safe to invoke a method from the same enclosing class. return true; } @@ -330,7 +333,7 @@ // Conservatively report an illegal access. return false; } - if (holder.isSamePackage(context)) { + if (holder.isSamePackage(context.getHolderType())) { // The class must be accessible (note that we have already established that the method is not // private). return !clazz.accessFlags.isPrivate();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java index eac97c1..cbcbd2e 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java
@@ -78,8 +78,7 @@ TypeElement.fromDexType(invokedMethod.holder, definitelyNotNull(), appView); dynamicLowerBoundType = null; } else { - DexEncodedMethod singleTarget = - invoke.lookupSingleTarget(appView, code.method().holder()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, code.context()); if (singleTarget == null) { continue; } @@ -96,7 +95,8 @@ } } else if (current.isStaticGet()) { StaticGet staticGet = current.asStaticGet(); - DexEncodedField encodedField = appView.appInfo().resolveField(staticGet.getField()); + DexEncodedField encodedField = + appView.appInfo().resolveField(staticGet.getField()).getResolvedField(); if (encodedField == null) { continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java index 62b5ab3..b1af390 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
@@ -9,7 +9,7 @@ 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.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.BasicBlock; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Instruction; @@ -110,7 +110,7 @@ } }); - DexType context = code.method().holder(); + ProgramMethod context = code.context(); // Collect invocations along with arguments. for (BasicBlock block : code.blocks) { for (Instruction current : block.getInstructions()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java index 6db2341..bb58ce1 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -147,22 +147,22 @@ } private ConstraintWithTarget instructionAllowedForInlining( - Instruction instruction, InliningConstraints inliningConstraints, DexType invocationContext) { - ConstraintWithTarget result = - instruction.inliningConstraint(inliningConstraints, invocationContext); + Instruction instruction, InliningConstraints inliningConstraints, ProgramMethod context) { + ConstraintWithTarget result = instruction.inliningConstraint(inliningConstraints, context); if (result == ConstraintWithTarget.NEVER && instruction.isDebugInstruction()) { return ConstraintWithTarget.ALWAYS; } return result; } - public ConstraintWithTarget computeInliningConstraint(IRCode code, ProgramMethod method) { + public ConstraintWithTarget computeInliningConstraint(IRCode code) { if (containsPotentialCatchHandlerVerificationError(code)) { return ConstraintWithTarget.NEVER; } + ProgramMethod context = code.context(); if (appView.options().canHaveDalvikIntUsedAsNonIntPrimitiveTypeBug() - && returnsIntAsBoolean(code, method)) { + && returnsIntAsBoolean(code, context)) { return ConstraintWithTarget.NEVER; } @@ -171,7 +171,7 @@ new InliningConstraints(appView, GraphLense.getIdentityLense()); for (Instruction instruction : code.instructions()) { ConstraintWithTarget state = - instructionAllowedForInlining(instruction, inliningConstraints, method.getHolderType()); + instructionAllowedForInlining(instruction, inliningConstraints, context); if (state == ConstraintWithTarget.NEVER) { result = state; break; @@ -198,28 +198,27 @@ return false; } - boolean hasInliningAccess(ProgramMethod method, ProgramMethod target) { - if (!isVisibleWithFlags( - target.getHolderType(), method.getHolderType(), target.getDefinition().accessFlags)) { + boolean hasInliningAccess(ProgramMethod context, ProgramMethod target) { + if (!isVisibleWithFlags(target.getHolderType(), context, target.getDefinition().accessFlags)) { return false; } // The class needs also to be visible for us to have access. - return isVisibleWithFlags( - target.getHolderType(), method.getHolderType(), target.getHolder().accessFlags); + return isVisibleWithFlags(target.getHolderType(), context, target.getHolder().accessFlags); } - private boolean isVisibleWithFlags(DexType target, DexType context, AccessFlags<?> flags) { + private boolean isVisibleWithFlags(DexType target, ProgramMethod context, AccessFlags<?> flags) { if (flags.isPublic()) { return true; } if (flags.isPrivate()) { - return NestUtils.sameNest(target, context, appView); + return NestUtils.sameNest(target, context.getHolderType(), appView); } if (flags.isProtected()) { - return appView.appInfo().isSubtype(context, target) || target.isSamePackage(context); + return appView.appInfo().isSubtype(context.getHolderType(), target) + || target.isSamePackage(context.getHolderType()); } // package-private - return target.isSamePackage(context); + return target.isSamePackage(context.getHolderType()); } public synchronized boolean isDoubleInlineSelectedTarget(ProgramMethod method) { @@ -367,36 +366,36 @@ } public static ConstraintWithTarget deriveConstraint( - DexType contextHolder, DexType targetHolder, AccessFlags flags, AppView<?> appView) { + DexProgramClass context, DexType targetHolder, AccessFlags<?> flags, AppView<?> appView) { if (flags.isPublic()) { return ALWAYS; } else if (flags.isPrivate()) { - DexClass contextHolderClass = appView.definitionFor(contextHolder); - assert contextHolderClass != null; - if (contextHolderClass.isInANest()) { - return NestUtils.sameNest(contextHolder, targetHolder, appView) + if (context.isInANest()) { + return NestUtils.sameNest(context.getType(), targetHolder, appView) ? new ConstraintWithTarget(Constraint.SAMENEST, targetHolder) : NEVER; } - return targetHolder == contextHolder - ? new ConstraintWithTarget(Constraint.SAMECLASS, targetHolder) : NEVER; + return targetHolder == context.type + ? new ConstraintWithTarget(Constraint.SAMECLASS, targetHolder) + : NEVER; } else if (flags.isProtected()) { - if (targetHolder.isSamePackage(contextHolder)) { + if (targetHolder.isSamePackage(context.type)) { // Even though protected, this is visible via the same package from the context. return new ConstraintWithTarget(Constraint.PACKAGE, targetHolder); - } else if (appView.isSubtype(contextHolder, targetHolder).isTrue()) { + } else if (appView.isSubtype(context.type, targetHolder).isTrue()) { return new ConstraintWithTarget(Constraint.SUBCLASS, targetHolder); } return NEVER; } else { /* package-private */ - return targetHolder.isSamePackage(contextHolder) - ? new ConstraintWithTarget(Constraint.PACKAGE, targetHolder) : NEVER; + return targetHolder.isSamePackage(context.type) + ? new ConstraintWithTarget(Constraint.PACKAGE, targetHolder) + : NEVER; } } public static ConstraintWithTarget classIsVisible( - DexType context, DexType clazz, AppView<?> appView) { + DexProgramClass context, DexType clazz, AppView<?> appView) { if (clazz.isArrayType()) { return classIsVisible(context, clazz.toArrayElementType(appView.dexItemFactory()), appView); } @@ -966,8 +965,7 @@ // TODO(b/142116551): This should be equivalent to invoke.lookupSingleTarget()! ProgramMethod singleTarget = oracle.lookupSingleTarget(invoke, context); if (singleTarget == null) { - WhyAreYouNotInliningReporter.handleInvokeWithUnknownTarget( - invoke, appView, context.getDefinition()); + WhyAreYouNotInliningReporter.handleInvokeWithUnknownTarget(invoke, appView, context); continue; } @@ -975,8 +973,7 @@ WhyAreYouNotInliningReporter whyAreYouNotInliningReporter = oracle.isForcedInliningOracle() ? NopWhyAreYouNotInliningReporter.getInstance() - : WhyAreYouNotInliningReporter.createFor( - singleTargetMethod, appView, context.getDefinition()); + : WhyAreYouNotInliningReporter.createFor(singleTarget, appView, context); InlineAction action = oracle.computeInlining( invoke,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java index ea77caf..890a23e 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -90,16 +90,16 @@ } public ConstraintWithTarget forDexItemBasedConstString( - DexReference type, DexType invocationContext) { + DexReference type, DexProgramClass context) { return ConstraintWithTarget.ALWAYS; } - public ConstraintWithTarget forCheckCast(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forCheckCast(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } - public ConstraintWithTarget forConstClass(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forConstClass(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } public ConstraintWithTarget forConstInstruction() { @@ -126,42 +126,40 @@ return ConstraintWithTarget.ALWAYS; } - public ConstraintWithTarget forInitClass(DexType clazz, DexType context) { + public ConstraintWithTarget forInitClass(DexType clazz, DexProgramClass context) { return ConstraintWithTarget.classIsVisible(context, clazz, appView); } - public ConstraintWithTarget forInstanceGet(DexField field, DexType invocationContext) { + public ConstraintWithTarget forInstanceGet(DexField field, DexProgramClass context) { DexField lookup = graphLense.lookupField(field); - return forFieldInstruction( - lookup, appView.appInfo().lookupInstanceTarget(lookup.holder, lookup), invocationContext); + return forFieldInstruction(lookup, appView.appInfo().lookupInstanceTarget(lookup), context); } - public ConstraintWithTarget forInstanceOf(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forInstanceOf(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } - public ConstraintWithTarget forInstancePut(DexField field, DexType invocationContext) { + public ConstraintWithTarget forInstancePut(DexField field, DexProgramClass context) { DexField lookup = graphLense.lookupField(field); - return forFieldInstruction( - lookup, appView.appInfo().lookupInstanceTarget(lookup.holder, lookup), invocationContext); + return forFieldInstruction(lookup, appView.appInfo().lookupInstanceTarget(lookup), context); } - public ConstraintWithTarget forInvoke(DexMethod method, Type type, DexType invocationContext) { + public ConstraintWithTarget forInvoke(DexMethod method, Type type, DexProgramClass context) { switch (type) { case DIRECT: - return forInvokeDirect(method, invocationContext); + return forInvokeDirect(method, context); case INTERFACE: - return forInvokeInterface(method, invocationContext); + return forInvokeInterface(method, context); case STATIC: - return forInvokeStatic(method, invocationContext); + return forInvokeStatic(method, context); case SUPER: - return forInvokeSuper(method, invocationContext); + return forInvokeSuper(method, context); case VIRTUAL: - return forInvokeVirtual(method, invocationContext); + return forInvokeVirtual(method, context); case CUSTOM: return forInvokeCustom(); case POLYMORPHIC: - return forInvokePolymorphic(method, invocationContext); + return forInvokePolymorphic(method, context); default: throw new Unreachable("Unexpected type: " + type); } @@ -174,17 +172,13 @@ private DexEncodedMethod lookupWhileVerticalClassMerging( DexMethod method, - DexType invocationContext, + DexProgramClass context, BiFunction<SingleResolutionResult, DexProgramClass, DexEncodedMethod> lookupFunction) { SingleResolutionResult singleResolutionResult = - appView.appInfo().resolveMethod(method.holder, method).asSingleResolution(); + appView.appInfo().unsafeResolveMethodDueToDexFormat(method).asSingleResolution(); if (singleResolutionResult == null) { return null; } - DexProgramClass context = appView.definitionForProgramType(invocationContext); - if (context == null) { - return null; - } DexEncodedMethod dexEncodedMethod = lookupFunction.apply(singleResolutionResult, context); if (dexEncodedMethod != null) { return dexEncodedMethod; @@ -203,61 +197,55 @@ return null; } - public ConstraintWithTarget forInvokeDirect(DexMethod method, DexType invocationContext) { + public ConstraintWithTarget forInvokeDirect(DexMethod method, DexProgramClass context) { DexMethod lookup = graphLense.lookupMethod(method); DexEncodedMethod target = isVerticalClassMerging() ? lookupWhileVerticalClassMerging( lookup, - invocationContext, + context, (res, ctxt) -> res.lookupInvokeDirectTarget(ctxt, appView.appInfo())) - : appView.appInfo().lookupDirectTarget(lookup, invocationContext); - return forSingleTargetInvoke(lookup, target, invocationContext); + : appView.appInfo().lookupDirectTarget(lookup, context); + return forSingleTargetInvoke(lookup, target, context); } - public ConstraintWithTarget forInvokeInterface(DexMethod method, DexType invocationContext) { + public ConstraintWithTarget forInvokeInterface(DexMethod method, DexProgramClass context) { DexMethod lookup = graphLense.lookupMethod(method); - return forVirtualInvoke( - lookup, - invocationContext, - true); + return forVirtualInvoke(lookup, context, true); } - public ConstraintWithTarget forInvokeMultiNewArray(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forInvokeMultiNewArray(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } - public ConstraintWithTarget forInvokeNewArray(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forInvokeNewArray(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } - public ConstraintWithTarget forInvokePolymorphic(DexMethod method, DexType invocationContext) { + public ConstraintWithTarget forInvokePolymorphic(DexMethod method, DexProgramClass context) { return ConstraintWithTarget.NEVER; } - public ConstraintWithTarget forInvokeStatic(DexMethod method, DexType invocationContext) { + public ConstraintWithTarget forInvokeStatic(DexMethod method, DexProgramClass context) { DexMethod lookup = graphLense.lookupMethod(method); DexEncodedMethod target = isVerticalClassMerging() ? lookupWhileVerticalClassMerging( lookup, - invocationContext, + context, (res, ctxt) -> res.lookupInvokeStaticTarget(ctxt, appView.appInfo())) - : appView.appInfo().lookupStaticTarget(lookup, invocationContext); - return forSingleTargetInvoke(lookup, target, invocationContext); + : appView.appInfo().lookupStaticTarget(lookup, context); + return forSingleTargetInvoke(lookup, target, context); } - public ConstraintWithTarget forInvokeSuper(DexMethod method, DexType invocationContext) { + public ConstraintWithTarget forInvokeSuper(DexMethod method, DexProgramClass context) { // The semantics of invoke super depend on the context. - return new ConstraintWithTarget(Constraint.SAMECLASS, invocationContext); + return new ConstraintWithTarget(Constraint.SAMECLASS, context.type); } - public ConstraintWithTarget forInvokeVirtual(DexMethod method, DexType invocationContext) { + public ConstraintWithTarget forInvokeVirtual(DexMethod method, DexProgramClass context) { DexMethod lookup = graphLense.lookupMethod(method); - return forVirtualInvoke( - lookup, - invocationContext, - false); + return forVirtualInvoke(lookup, context, false); } public ConstraintWithTarget forJumpInstruction() { @@ -280,16 +268,16 @@ return ConstraintWithTarget.ALWAYS; } - public ConstraintWithTarget forNewArrayEmpty(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forNewArrayEmpty(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } public ConstraintWithTarget forNewArrayFilledData() { return ConstraintWithTarget.ALWAYS; } - public ConstraintWithTarget forNewInstance(DexType type, DexType invocationContext) { - return ConstraintWithTarget.classIsVisible(invocationContext, type, appView); + public ConstraintWithTarget forNewInstance(DexType type, DexProgramClass context) { + return ConstraintWithTarget.classIsVisible(context, type, appView); } public ConstraintWithTarget forAssume() { @@ -304,16 +292,14 @@ return ConstraintWithTarget.ALWAYS; } - public ConstraintWithTarget forStaticGet(DexField field, DexType invocationContext) { + public ConstraintWithTarget forStaticGet(DexField field, DexProgramClass context) { DexField lookup = graphLense.lookupField(field); - return forFieldInstruction( - lookup, appView.appInfo().lookupStaticTarget(lookup.holder, lookup), invocationContext); + return forFieldInstruction(lookup, appView.appInfo().lookupStaticTarget(lookup), context); } - public ConstraintWithTarget forStaticPut(DexField field, DexType invocationContext) { + public ConstraintWithTarget forStaticPut(DexField field, DexProgramClass context) { DexField lookup = graphLense.lookupField(field); - return forFieldInstruction( - lookup, appView.appInfo().lookupStaticTarget(lookup.holder, lookup), invocationContext); + return forFieldInstruction(lookup, appView.appInfo().lookupStaticTarget(lookup), context); } public ConstraintWithTarget forStore() { @@ -341,17 +327,16 @@ } private ConstraintWithTarget forFieldInstruction( - DexField field, DexEncodedField target, DexType invocationContext) { + DexField field, DexEncodedField target, DexProgramClass context) { // Resolve the field if possible and decide whether the instruction can inlined. DexType fieldHolder = graphLense.lookupType(field.holder); DexClass fieldClass = appView.definitionFor(fieldHolder); if (target != null && fieldClass != null) { ConstraintWithTarget fieldConstraintWithTarget = - ConstraintWithTarget.deriveConstraint( - invocationContext, fieldHolder, target.accessFlags, appView); + ConstraintWithTarget.deriveConstraint(context, fieldHolder, target.accessFlags, appView); // If the field has not been member-rebound, then we also need to make sure that the - // `invocationContext` has access to the definition of the field. + // `context` has access to the definition of the field. // // See, for example, InlineNonReboundFieldTest (b/128604123). if (field.holder != target.holder()) { @@ -360,13 +345,13 @@ ConstraintWithTarget.meet( fieldConstraintWithTarget, ConstraintWithTarget.deriveConstraint( - invocationContext, actualFieldHolder, target.accessFlags, appView), + context, actualFieldHolder, target.accessFlags, appView), appView); } ConstraintWithTarget classConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - invocationContext, fieldHolder, fieldClass.accessFlags, appView); + context, fieldHolder, fieldClass.accessFlags, appView); return ConstraintWithTarget.meet( fieldConstraintWithTarget, classConstraintWithTarget, appView); } @@ -374,7 +359,7 @@ } private ConstraintWithTarget forSingleTargetInvoke( - DexMethod method, DexEncodedMethod target, DexType invocationContext) { + DexMethod method, DexEncodedMethod target, DexProgramClass context) { if (method.holder.isArrayType()) { return ConstraintWithTarget.ALWAYS; } @@ -389,11 +374,11 @@ ConstraintWithTarget methodConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - invocationContext, methodHolder, target.accessFlags, appView); + context, methodHolder, target.accessFlags, appView); // We also have to take the constraint of the enclosing class into account. ConstraintWithTarget classConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - invocationContext, methodHolder, methodClass.accessFlags, appView); + context, methodHolder, methodClass.accessFlags, appView); return ConstraintWithTarget.meet( methodConstraintWithTarget, classConstraintWithTarget, appView); } @@ -402,17 +387,14 @@ } private ConstraintWithTarget forVirtualInvoke( - DexMethod method, - DexType invocationContext, - boolean isInterface) { + DexMethod method, DexProgramClass context, boolean isInterface) { if (method.holder.isArrayType()) { return ConstraintWithTarget.ALWAYS; } // Perform resolution and derive inlining constraints based on the accessibility of the // resolution result. - ResolutionResult resolutionResult = - appView.appInfo().resolveMethod(method.holder, method, isInterface); + ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method, isInterface); if (!resolutionResult.isVirtualTarget()) { return ConstraintWithTarget.NEVER; } @@ -428,7 +410,7 @@ assert methodClass != null; ConstraintWithTarget methodConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - invocationContext, methodHolder, resolutionTarget.accessFlags, appView); + context, methodHolder, resolutionTarget.accessFlags, appView); // We also have to take the constraint of the enclosing class of the resolution result // into account. We do not allow inlining this method if it is calling something that // is inaccessible. Inlining in that case could move the code to another package making a @@ -436,7 +418,7 @@ // we have to make sure that inlining cannot make it inaccessible. ConstraintWithTarget classConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - invocationContext, methodHolder, methodClass.accessFlags, appView); + context, methodHolder, methodClass.accessFlags, appView); return ConstraintWithTarget.meet( methodConstraintWithTarget, classConstraintWithTarget, appView); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java index 458f4b1..8222958 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -146,7 +146,7 @@ DexField field = returnValueRule.getField(); assert instruction.getOutType() == TypeElement.fromDexType(field.type, maybeNull(), appView); - DexEncodedField staticField = appView.appInfo().lookupStaticTarget(field.holder, field); + DexEncodedField staticField = appView.appInfo().lookupStaticTarget(field); if (staticField == null) { if (warnedFields.add(field)) { reporter.warning( @@ -212,7 +212,7 @@ if (current.isStaticGet()) { StaticGet staticGet = current.asStaticGet(); replaceInstructionByInitClassIfPossible( - staticGet, staticGet.getField().holder, code, iterator, code.method().holder()); + staticGet, staticGet.getField().holder, code, iterator, code.context()); } replacement.setPosition(position); if (block.hasCatchHandlers()) { @@ -236,7 +236,7 @@ if (!invokedHolder.isClassType()) { return; } - DexEncodedMethod target = current.lookupSingleTarget(appView, context.getHolderType()); + DexEncodedMethod target = current.lookupSingleTarget(appView, context); if (target != null && target.isInstanceInitializer()) { // Member value propagation does not apply to constructors. Removing a call to a constructor // that is marked as having no side effects could lead to verification errors, due to @@ -250,7 +250,7 @@ // references that have actual definitions are marked by the root set builder. So, here, we // try again with a resolved target, not the direct definition, which may not exist. DexEncodedMethod resolutionTarget = - appView.appInfo().resolveMethod(invokedHolder, invokedMethod).getSingleTarget(); + appView.appInfo().unsafeResolveMethodDueToDexFormat(invokedMethod).getSingleTarget(); lookup = lookupMemberRule(resolutionTarget); } boolean invokeReplaced = false; @@ -303,10 +303,10 @@ current.setOutValue(null); if (current.isInvokeMethodWithReceiver()) { - replaceInstructionByNullCheckIfPossible(current, iterator, context.getHolderType()); + replaceInstructionByNullCheckIfPossible(current, iterator, context); } else if (current.isInvokeStatic()) { replaceInstructionByInitClassIfPossible( - current, target.holder(), code, iterator, context.getHolderType()); + current, target.holder(), code, iterator, context); } // Insert the definition of the replacement. @@ -330,7 +330,7 @@ DexField field = current.getField(); // TODO(b/123857022): Should be able to use definitionFor(). - DexEncodedField target = appView.appInfo().resolveField(field); + DexEncodedField target = appView.appInfo().resolveField(field).getResolvedField(); if (target == null) { boolean replaceCurrentInstructionWithConstNull = appView.withGeneratedExtensionRegistryShrinker( @@ -367,7 +367,7 @@ abstractValue = target.getOptimizationInfo().getAbstractValue(); if (abstractValue.isUnknown() && !target.isStatic()) { AbstractValue abstractReceiverValue = - current.asInstanceGet().object().getAbstractValue(appView, code.method().holder()); + current.asInstanceGet().object().getAbstractValue(appView, code.context()); if (abstractReceiverValue.isSingleFieldValue()) { abstractValue = abstractReceiverValue.asSingleFieldValue().getState().getAbstractFieldValue(target); @@ -393,7 +393,7 @@ } if (singleValue.isMaterializableInContext(appView, code.context())) { BasicBlock block = current.getBlock(); - DexType context = code.method().holder(); + ProgramMethod context = code.context(); Position position = current.getPosition(); // All usages are replaced by the replacement value. @@ -425,7 +425,7 @@ } private void replaceInstructionByNullCheckIfPossible( - Instruction instruction, InstructionListIterator iterator, DexType context) { + Instruction instruction, InstructionListIterator iterator, ProgramMethod context) { assert instruction.isInstanceFieldInstruction() || instruction.isInvokeMethodWithReceiver(); assert !instruction.hasOutValue() || !instruction.outValue().hasAnyUsers(); if (instruction.instructionMayHaveSideEffects( @@ -456,7 +456,7 @@ DexType holder, IRCode code, InstructionListIterator iterator, - DexType context) { + ProgramMethod context) { assert instruction.isStaticFieldInstruction() || instruction.isInvokeStatic(); if (instruction.instructionMayHaveSideEffects( appView, context, Instruction.SideEffectAssumption.CLASS_ALREADY_INITIALIZED)) { @@ -467,7 +467,7 @@ appView, // Types that are a super type of `context` are guaranteed to be initialized // already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.appInfo().isSubtype(context.getHolderType(), type), Sets.newIdentityHashSet()); if (!classInitializationMayHaveSideEffects) { iterator.removeOrReplaceByDebugLocalRead(); @@ -485,7 +485,7 @@ private void replaceInstancePutByNullCheckIfNeverRead( IRCode code, InstructionListIterator iterator, InstancePut current) { - DexEncodedField target = appView.appInfo().resolveField(current.getField()); + DexEncodedField target = appView.appInfo().resolveField(current.getField()).getResolvedField(); if (target == null || appView.appInfo().isFieldRead(target)) { return; } @@ -494,12 +494,12 @@ return; } - replaceInstructionByNullCheckIfPossible(current, iterator, code.method().holder()); + replaceInstructionByNullCheckIfPossible(current, iterator, code.context()); } private void replaceStaticPutByInitClassIfNeverRead( IRCode code, InstructionListIterator iterator, StaticPut current) { - DexEncodedField field = appView.appInfo().resolveField(current.getField()); + DexEncodedField field = appView.appInfo().resolveField(current.getField()).getResolvedField(); if (field == null || appView.appInfo().isFieldRead(field)) { return; } @@ -509,7 +509,7 @@ } replaceInstructionByInitClassIfPossible( - current, field.holder(), code, iterator, code.method().holder()); + current, field.holder(), code, iterator, code.context()); } /**
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java index 662eb39..406c09c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -5,11 +5,11 @@ import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedField; 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.ir.analysis.type.TypeAnalysis; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -43,17 +43,17 @@ public class NonNullTracker implements Assumer { - private final AppView<?> appView; - private final DexItemFactory dexItemFactory; + private final AppView<? extends AppInfoWithClassHierarchy> appView; private final Consumer<BasicBlock> splitBlockConsumer; - public NonNullTracker(AppView<?> appView) { + public NonNullTracker(AppView<? extends AppInfoWithClassHierarchy> appView) { this(appView, null); } - public NonNullTracker(AppView<?> appView, Consumer<BasicBlock> splitBlockConsumer) { + public NonNullTracker( + AppView<? extends AppInfoWithClassHierarchy> appView, + Consumer<BasicBlock> splitBlockConsumer) { this.appView = appView; - this.dexItemFactory = appView.dexItemFactory(); this.splitBlockConsumer = splitBlockConsumer; } @@ -89,8 +89,7 @@ InvokeMethod invoke = current.asInvokeMethod(); DexMethod invokedMethod = invoke.getInvokedMethod(); - DexEncodedMethod singleTarget = - invoke.lookupSingleTarget(appView, code.method().holder()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, code.context()); if (singleTarget != null) { MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo(); @@ -119,7 +118,7 @@ FieldInstruction fieldInstruction = current.asFieldInstruction(); DexField field = fieldInstruction.getField(); if (field.type.isReferenceType() && isNullableReferenceTypeWithUsers(outValue)) { - DexEncodedField encodedField = appView.appInfo().resolveField(field); + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField != null) { FieldOptimizationInfo optimizationInfo = encodedField.getOptimizationInfo(); if (optimizationInfo.getDynamicUpperBoundType() != null
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java index 2b9456a..5c4197c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -66,10 +66,14 @@ import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.InternalOptions.OutlineOptions; import com.android.tools.r8.utils.ListUtils; +import com.android.tools.r8.utils.ProgramMethodEquivalence; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.StringUtils.BraceType; import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder; import com.android.tools.r8.utils.collections.ProgramMethodSet; +import com.google.common.base.Equivalence.Wrapper; +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -108,7 +112,7 @@ public class Outliner { /** Result of first step (see {@link Outliner#createOutlineMethodIdentifierGenerator()}. */ - private final List<List<ProgramMethod>> candidateMethodLists = new ArrayList<>(); + private final List<Multiset<Wrapper<ProgramMethod>>> candidateMethodLists = new ArrayList<>(); /** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */ private final LongLivedProgramMethodSetBuilder methodsSelectedForOutlining = new LongLivedProgramMethodSetBuilder(); @@ -863,8 +867,7 @@ // See whether we could move this invoke somewhere else. We reuse the logic from inlining // here, as the constraints are the same. - ConstraintWithTarget constraint = - invoke.inliningConstraint(inliningConstraints, method.getHolderType()); + ConstraintWithTarget constraint = invoke.inliningConstraint(inliningConstraints, method); if (constraint != ConstraintWithTarget.ALWAYS) { return false; } @@ -1135,10 +1138,12 @@ // TODO(sgjesse): This does not take several usages in the same method into account. private class OutlineMethodIdentifier extends OutlineSpotter { - private final Map<Outline, List<ProgramMethod>> candidateMap; + private final Map<Outline, Multiset<Wrapper<ProgramMethod>>> candidateMap; OutlineMethodIdentifier( - ProgramMethod method, BasicBlock block, Map<Outline, List<ProgramMethod>> candidateMap) { + ProgramMethod method, + BasicBlock block, + Map<Outline, Multiset<Wrapper<ProgramMethod>>> candidateMap) { super(method, block); this.candidateMap = candidateMap; } @@ -1146,12 +1151,14 @@ @Override protected void handle(int start, int end, Outline outline) { synchronized (candidateMap) { - candidateMap.computeIfAbsent(outline, this::addOutlineMethodList).add(method); + candidateMap + .computeIfAbsent(outline, this::addOutlineMethodList) + .add(ProgramMethodEquivalence.get().wrap(method)); } } - private List<ProgramMethod> addOutlineMethodList(Outline outline) { - List<ProgramMethod> result = new ArrayList<>(); + private Multiset<Wrapper<ProgramMethod>> addOutlineMethodList(Outline outline) { + Multiset<Wrapper<ProgramMethod>> result = HashMultiset.create(); candidateMethodLists.add(result); return result; } @@ -1277,7 +1284,7 @@ // out-value of invokes to null), this map must not be used except for identifying methods // potentially relevant to outlining. OutlineMethodIdentifier will add method lists to // candidateMethodLists whenever it adds an entry to candidateMap. - Map<Outline, List<ProgramMethod>> candidateMap = new HashMap<>(); + Map<Outline, Multiset<Wrapper<ProgramMethod>>> candidateMap = new HashMap<>(); assert candidateMethodLists.isEmpty(); assert outlineMethodIdentifierGenerator == null; outlineMethodIdentifierGenerator = @@ -1311,9 +1318,9 @@ public boolean selectMethodsForOutlining() { assert methodsSelectedForOutlining.isEmpty(); assert outlineSites.isEmpty(); - for (List<ProgramMethod> outlineMethods : candidateMethodLists) { + for (Multiset<Wrapper<ProgramMethod>> outlineMethods : candidateMethodLists) { if (outlineMethods.size() >= appView.options().outline.threshold) { - methodsSelectedForOutlining.addAll(outlineMethods); + outlineMethods.forEach(wrapper -> methodsSelectedForOutlining.add(wrapper.get())); } } candidateMethodLists.clear();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java index 1ba460e..ef81097 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -152,7 +152,7 @@ private DexEncodedField resolveField(DexField field) { if (appView.enableWholeProgramOptimizations()) { - return appView.appInfo().resolveField(field); + return appView.appInfo().withLiveness().resolveField(field).getResolvedField(); } if (field.holder == method.getHolderType()) { return appView.definitionFor(field); @@ -161,7 +161,6 @@ } public void run() { - DexType context = method.getHolderType(); Reference2IntMap<BasicBlock> pendingNormalSuccessors = new Reference2IntOpenHashMap<>(); for (BasicBlock block : code.blocks) { if (!block.hasUniqueNormalSuccessor()) { @@ -274,14 +273,14 @@ appView, // Types that are a super type of `context` are guaranteed to be initialized // already. - type -> appView.isSubtype(context, type).isTrue(), + type -> appView.isSubtype(method.getHolderType(), type).isTrue(), Sets.newIdentityHashSet())) { killAllNonFinalActiveFields(); } } else { // If the current instruction could trigger a method invocation, it could also cause // field values to change. In that case, it must be handled above. - assert !instruction.instructionMayTriggerMethodInvocation(appView, context); + assert !instruction.instructionMayTriggerMethodInvocation(appView, method); // If this assertion fails for a new instruction we need to determine if that // instruction has side-effects that can change the value of fields. If so, it must be @@ -348,7 +347,7 @@ return; } - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.getHolderType()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method); if (singleTarget == null || !singleTarget.isInstanceInitializer()) { killAllNonFinalActiveFields(); return;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java index 1f410ef..fd270a4 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -39,7 +40,7 @@ return; } Set<Value> affectedValues = Sets.newIdentityHashSet(); - DexType context = code.method().holder(); + ProgramMethod context = code.context(); ClassInitializationAnalysis classInitializationAnalysis = new ClassInitializationAnalysis(appView, code); for (BasicBlock block : code.blocks) { @@ -84,9 +85,7 @@ } private static DexType getTypeForGetClass( - AppView<AppInfoWithLiveness> appView, - DexType context, - InvokeVirtual invoke) { + AppView<AppInfoWithLiveness> appView, ProgramMethod context, InvokeVirtual invoke) { DexItemFactory dexItemFactory = appView.dexItemFactory(); DexMethod invokedMethod = invoke.getInvokedMethod(); // Class<?> Object#getClass() is final and cannot be overridden. @@ -126,7 +125,7 @@ } // Make sure the target (base) type is visible. ConstraintWithTarget constraints = - ConstraintWithTarget.classIsVisible(context, baseType, appView); + ConstraintWithTarget.classIsVisible(context.getHolder(), baseType, appView); if (constraints == ConstraintWithTarget.NEVER) { return null; } @@ -136,7 +135,7 @@ private static DexType getTypeForClassForName( AppView<AppInfoWithLiveness> appView, ClassInitializationAnalysis classInitializationAnalysis, - DexType context, + ProgramMethod context, InvokeStatic invoke) { DexItemFactory dexItemFactory = appView.dexItemFactory(); DexMethod invokedMethod = invoke.getInvokedMethod(); @@ -203,7 +202,7 @@ } // Make sure the (base) type is visible. ConstraintWithTarget constraints = - ConstraintWithTarget.classIsVisible(context, baseType, appView); + ConstraintWithTarget.classIsVisible(context.getHolder(), baseType, appView); if (constraints == ConstraintWithTarget.NEVER) { return null; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java index 055f575..32bea32 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLense.NestedGraphLense; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.RewrittenPrototypeDescription; import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection; import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo; @@ -351,8 +352,7 @@ Instruction instruction = instructionIterator.next(); if (instruction.throwsOnNullInput()) { Value couldBeNullValue = instruction.getNonNullInput(); - if (isThrowNullCandidate( - couldBeNullValue, instruction, appView, code.method().holder())) { + if (isThrowNullCandidate(couldBeNullValue, instruction, appView, code.context())) { if (instruction.isInstanceGet() || instruction.isInstancePut()) { ++numberOfInstanceGetOrInstancePutWithNullReceiver; } else if (instruction.isInvokeMethodWithReceiver()) { @@ -405,7 +405,7 @@ Value couldBeNullValue, Instruction current, AppView<? extends AppInfoWithClassHierarchy> appView, - DexType context) { + ProgramMethod context) { if (!couldBeNullValue.isAlwaysNull(appView)) { return false; } @@ -451,12 +451,12 @@ IRCode code, AssumeDynamicTypeRemover assumeDynamicTypeRemover, Set<Value> affectedValues) { - DexType context = code.method().holder(); + ProgramMethod context = code.context(); DexField field = instruction.getField(); DexType fieldType = field.type; if (fieldType.isAlwaysNull(appView)) { // TODO(b/123857022): Should be possible to use definitionFor(). - DexEncodedField encodedField = appView.appInfo().resolveField(field); + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField == null) { return; } @@ -507,7 +507,7 @@ AssumeDynamicTypeRemover assumeDynamicTypeRemover, Set<BasicBlock> blocksToBeRemoved, Set<Value> affectedValues) { - DexEncodedMethod target = invoke.lookupSingleTarget(appView, code.method().holder()); + DexEncodedMethod target = invoke.lookupSingleTarget(appView, code.context()); if (target == null) { return; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java index 59e9a94..9318acb 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -172,10 +172,10 @@ assert root.isStaticGet(); StaticGet staticGet = root.asStaticGet(); - if (staticGet.instructionMayHaveSideEffects(appView, method.getHolderType())) { + if (staticGet.instructionMayHaveSideEffects(appView, method)) { return EligibilityStatus.RETRIEVAL_MAY_HAVE_SIDE_EFFECTS; } - DexEncodedField field = appView.appInfo().resolveField(staticGet.getField()); + DexEncodedField field = appView.appInfo().resolveField(staticGet.getField()).getResolvedField(); FieldOptimizationInfo optimizationInfo = field.getOptimizationInfo(); ClassTypeElement dynamicLowerBoundType = optimizationInfo.getDynamicLowerBoundType(); if (dynamicLowerBoundType == null @@ -221,7 +221,14 @@ while (!currentUsers.isEmpty()) { Set<Instruction> indirectUsers = Sets.newIdentityHashSet(); for (Instruction user : currentUsers) { - if (user.isAssume()) { + if (user.isAssume() || user.isCheckCast()) { + if (user.isCheckCast()) { + boolean isCheckCastUnsafe = + !appView.appInfo().isSubtype(eligibleClass.type, user.asCheckCast().getType()); + if (isCheckCastUnsafe) { + return user; // Not eligible. + } + } Value alias = user.outValue(); if (receivers.isReceiverAlias(alias)) { continue; // Already processed. @@ -242,7 +249,10 @@ return user; // Not eligible. } DexEncodedField field = - appView.appInfo().resolveField(user.asFieldInstruction().getField()); + appView + .appInfo() + .resolveField(user.asFieldInstruction().getField()) + .getResolvedField(); if (field == null || field.isStatic()) { return user; // Not eligible. } @@ -258,7 +268,10 @@ return user; // Not eligible. } DexEncodedField field = - appView.appInfo().resolveField(user.asFieldInstruction().getField()); + appView + .appInfo() + .resolveField(user.asFieldInstruction().getField()) + .getResolvedField(); if (field == null || field.isStatic()) { return user; // Not eligible. } @@ -267,8 +280,7 @@ if (user.isInvokeMethod()) { InvokeMethod invokeMethod = user.asInvokeMethod(); - DexEncodedMethod singleTargetMethod = - invokeMethod.lookupSingleTarget(appView, method.getHolderType()); + DexEncodedMethod singleTargetMethod = invokeMethod.lookupSingleTarget(appView, method); if (singleTargetMethod == null) { return user; // Not eligible. } @@ -513,7 +525,8 @@ continue; } - ProgramMethod singleTarget = invoke.lookupSingleProgramTarget(appView, method); + ProgramMethod singleTarget = + invoke.lookupSingleProgramTarget(appView, method, eligibleInstance); if (singleTarget == null || !indirectMethodCallsOnInstance.contains(singleTarget)) { throw new IllegalClassInlinerStateException(); } @@ -574,7 +587,7 @@ continue; } - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.getHolderType()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method); if (singleTarget != null) { Predicate<InvokeMethod> noSideEffectsPredicate = dexItemFactory.libraryMethodsWithoutSideEffects.getOrDefault( @@ -701,7 +714,10 @@ } InstancePut instancePut = user.asInstancePut(); DexEncodedField field = - appView.appInfo().resolveFieldOn(eligibleClass, instancePut.getField()); + appView + .appInfo() + .resolveFieldOn(eligibleClass, instancePut.getField()) + .getResolvedField(); if (field == null) { throw new Unreachable( "Unexpected field write left in method `" @@ -880,8 +896,8 @@ invoke, invoke.getInvokedMethod(), singleTarget, - eligibility -> - isEligibleInvokeWithAllUsersAsReceivers(eligibility, invoke, indirectUsers))) { + eligibility -> isEligibleInvokeWithAllUsersAsReceivers(eligibility, invoke, indirectUsers), + invoke.getType())) { return null; } @@ -892,15 +908,18 @@ } if (!eligibility.callsReceiver.isEmpty()) { assert eligibility.callsReceiver.get(0).getFirst() == Invoke.Type.VIRTUAL; - DexMethod indirectlyInvokedMethod = eligibility.callsReceiver.get(0).getSecond(); + Pair<Type, DexMethod> invokeInfo = eligibility.callsReceiver.get(0); + Type invokeType = invokeInfo.getFirst(); + DexMethod indirectlyInvokedMethod = invokeInfo.getSecond(); ResolutionResult resolutionResult = - appView.appInfo().resolveMethod(eligibleClass, indirectlyInvokedMethod); + appView.appInfo().resolveMethodOn(eligibleClass, indirectlyInvokedMethod); if (!resolutionResult.isSingleResolution()) { return null; } ProgramMethod indirectSingleTarget = resolutionResult.asSingleResolution().getResolutionPair().asProgramMethod(); - if (!isEligibleIndirectVirtualMethodCall(indirectlyInvokedMethod, indirectSingleTarget)) { + if (!isEligibleIndirectVirtualMethodCall( + indirectlyInvokedMethod, invokeType, indirectSingleTarget)) { return null; } indirectMethodCallsOnInstance.add(indirectSingleTarget); @@ -909,16 +928,16 @@ return new InliningInfo(singleTarget, eligibleClass.type); } - private boolean isEligibleIndirectVirtualMethodCall(DexMethod invokedMethod) { + private boolean isEligibleIndirectVirtualMethodCall(DexMethod invokedMethod, Type type) { ProgramMethod singleTarget = asProgramMethodOrNull( - appView.appInfo().resolveMethod(eligibleClass, invokedMethod).getSingleTarget(), + appView.appInfo().resolveMethodOn(eligibleClass, invokedMethod).getSingleTarget(), appView); - return isEligibleIndirectVirtualMethodCall(invokedMethod, singleTarget); + return isEligibleIndirectVirtualMethodCall(invokedMethod, type, singleTarget); } private boolean isEligibleIndirectVirtualMethodCall( - DexMethod invokedMethod, ProgramMethod singleTarget) { + DexMethod invokedMethod, Type type, ProgramMethod singleTarget) { if (!isEligibleSingleTarget(singleTarget)) { return false; } @@ -929,21 +948,23 @@ null, invokedMethod, singleTarget, - eligibility -> - eligibility.callsReceiver.isEmpty() && eligibility.returnsReceiver.isFalse()); + eligibility -> eligibility.callsReceiver.isEmpty() && eligibility.returnsReceiver.isFalse(), + type); } private boolean isEligibleVirtualMethodCall( InvokeMethodWithReceiver invoke, DexMethod callee, ProgramMethod singleTarget, - Predicate<ClassInlinerEligibilityInfo> eligibilityAcceptanceCheck) { + Predicate<ClassInlinerEligibilityInfo> eligibilityAcceptanceCheck, + Type type) { assert isEligibleSingleTarget(singleTarget); // We should not inline a method if the invocation has type interface or virtual and the // signature of the invocation resolves to a private or static method. // TODO(b/147212189): Why not inline private methods? If access is permitted it is valid. - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(callee.holder, callee); + ResolutionResult resolutionResult = + appView.appInfo().resolveMethod(callee, type == Type.INTERFACE); if (resolutionResult.isSingleResolution() && !resolutionResult.getSingleTarget().isNonPrivateVirtualMethod()) { return false; @@ -1152,7 +1173,7 @@ if (type == Type.VIRTUAL || type == Type.INTERFACE) { // Is the method called indirectly still eligible? - if (!isEligibleIndirectVirtualMethodCall(target)) { + if (!isEligibleIndirectVirtualMethodCall(target, type)) { return false; } } else if (type == Type.DIRECT) { @@ -1166,7 +1187,7 @@ } // Check if the method is inline-able by standard inliner. - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.getHolderType()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method); if (singleTarget == null) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java index 06c2894..b601000 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -394,7 +394,7 @@ return Reason.INVALID_INVOKE_ON_ARRAY; } DexEncodedMethod encodedSingleTarget = - invokeMethod.lookupSingleTarget(appView, code.method().holder()); + invokeMethod.lookupSingleTarget(appView, code.context()); if (encodedSingleTarget == null) { return Reason.INVALID_INVOKE; } @@ -459,7 +459,8 @@ // have identical enum type. if (instruction.isFieldPut()) { FieldInstruction fieldInstruction = instruction.asFieldInstruction(); - DexEncodedField field = appView.appInfo().resolveField(fieldInstruction.getField()); + DexEncodedField field = + appView.appInfo().resolveField(fieldInstruction.getField()).getResolvedField(); if (field == null) { return Reason.INVALID_FIELD_PUT; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java index 97d0029..1d6668c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -114,7 +114,7 @@ DexEncodedMethod singleTarget = appView .appInfo() - .resolveMethodOnClass(valueInfo.type, factory.objectMembers.toString) + .resolveMethodOnClass(factory.objectMembers.toString, valueInfo.type) .getSingleTarget(); if (singleTarget != null && singleTarget.method != factory.enumMethods.toString) { continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java index f4d341b..86d107a 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
@@ -6,15 +6,16 @@ import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull; import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.analysis.value.UnknownValue; import com.android.tools.r8.ir.code.Value; import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; import java.util.List; @@ -153,12 +154,10 @@ } public static CallSiteOptimizationInfo fromArguments( - AppView<? extends AppInfoWithClassHierarchy> appView, - DexEncodedMethod method, - List<Value> inValues) { + AppView<AppInfoWithLiveness> appView, ProgramMethod target, List<Value> inValues) { boolean allowConstantPropagation = appView.options().enablePropagationOfConstantsAtCallSites; ConcreteCallSiteOptimizationInfo newCallSiteInfo = - new ConcreteCallSiteOptimizationInfo(method, allowConstantPropagation); + new ConcreteCallSiteOptimizationInfo(target.getDefinition(), allowConstantPropagation); assert newCallSiteInfo.size == inValues.size(); assert newCallSiteInfo.dynamicUpperBoundTypes != null; for (int i = 0; i < newCallSiteInfo.size; i++) { @@ -167,8 +166,7 @@ assert newCallSiteInfo.constants != null; Value aliasedValue = arg.getAliasedValue(); if (!aliasedValue.isPhi()) { - AbstractValue abstractValue = - aliasedValue.definition.getAbstractValue(appView, method.holder()); + AbstractValue abstractValue = aliasedValue.definition.getAbstractValue(appView, target); if (abstractValue.isNonTrivial()) { newCallSiteInfo.constants.put(i, abstractValue); } @@ -181,7 +179,7 @@ assert arg.getType().isReferenceType(); newCallSiteInfo.dynamicUpperBoundTypes.put(i, arg.getDynamicUpperBoundType(appView)); } - if (newCallSiteInfo.hasUsefulOptimizationInfo(appView, method)) { + if (newCallSiteInfo.hasUsefulOptimizationInfo(appView, target.getDefinition())) { return newCallSiteInfo; } // As soon as we know the current call site does not have any useful optimization info,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java index 23b74b1..8bb40e0 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -44,13 +44,14 @@ import static com.android.tools.r8.ir.code.Opcodes.XOR; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; 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.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption; import com.android.tools.r8.ir.analysis.DeterminismAnalysis; @@ -128,9 +129,9 @@ InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos, Timing timing) { identifyBridgeInfo(method, code, feedback, timing); - identifyClassInlinerEligibility(method, code, feedback, timing); + identifyClassInlinerEligibility(code, feedback, timing); identifyParameterUsages(method, code, feedback, timing); - identifyReturnsArgument(method, code, feedback, timing); + identifyReturnsArgument(code, feedback, timing); if (options.enableInlining) { identifyInvokeSemanticsForInlining(method, code, feedback, timing); } @@ -152,14 +153,13 @@ } private void identifyClassInlinerEligibility( - DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) { + IRCode code, OptimizationFeedback feedback, Timing timing) { timing.begin("Identify class inliner eligibility"); - identifyClassInlinerEligibility(method, code, feedback); + identifyClassInlinerEligibility(code, feedback); timing.end(); } - private void identifyClassInlinerEligibility( - DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) { + private void identifyClassInlinerEligibility(IRCode code, OptimizationFeedback feedback) { // Method eligibility is calculated in similar way for regular method // and for the constructor. To be eligible method should only be using its // receiver in the following ways: @@ -173,24 +173,21 @@ // // Note that (4) can safely be removed as the receiver is guaranteed not to escape when we class // inline it, and hence any monitor instructions are no-ops. - boolean instanceInitializer = method.isInstanceInitializer(); - if (method.accessFlags.isNative() - || (!method.isNonAbstractVirtualMethod() && !instanceInitializer)) { + ProgramMethod context = code.context(); + DexEncodedMethod definition = context.getDefinition(); + boolean instanceInitializer = definition.isInstanceInitializer(); + if (definition.isNative() + || (!definition.isNonAbstractVirtualMethod() && !instanceInitializer)) { return; } - feedback.setClassInlinerEligibility(method, null); // To allow returns below. + feedback.setClassInlinerEligibility(definition, null); // To allow returns below. Value receiver = code.getThis(); if (receiver.numberOfPhiUsers() > 0) { return; } - DexClass clazz = appView.definitionFor(method.holder()); - if (clazz == null) { - return; - } - List<Pair<Invoke.Type, DexMethod>> callsReceiver = new ArrayList<>(); boolean seenSuperInitCall = false; boolean seenMonitor = false; @@ -224,11 +221,10 @@ } } DexField field = insn.asFieldInstruction().getField(); - if (appView.appInfo().resolveFieldOn(clazz, field) != null) { - // Require only accessing direct or indirect instance fields of the current class. - break; + if (appView.appInfo().resolveField(field).isFailedOrUnknownResolution()) { + return; } - return; + break; } case INVOKE_DIRECT: @@ -236,7 +232,7 @@ InvokeDirect invoke = insn.asInvokeDirect(); DexMethod invokedMethod = invoke.getInvokedMethod(); if (dexItemFactory.isConstructor(invokedMethod) - && invokedMethod.holder == clazz.superType + && invokedMethod.holder == context.getHolder().superType && ListUtils.lastIndexMatching(invoke.arguments(), isReceiverAlias) == 0 && !seenSuperInitCall && instanceInitializer) { @@ -250,7 +246,7 @@ case INVOKE_STATIC: { InvokeStatic invoke = insn.asInvokeStatic(); - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.holder()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context); if (singleTarget == null) { return; // Not allowed. } @@ -271,7 +267,7 @@ DexMethod invokedMethod = invoke.getInvokedMethod(); DexType returnType = invokedMethod.proto.returnType; if (returnType.isClassType() - && appView.appInfo().inSameHierarchy(returnType, method.holder())) { + && appView.appInfo().inSameHierarchy(returnType, context.getHolderType())) { return; // Not allowed, could introduce an alias of the receiver. } callsReceiver.add(new Pair<>(Invoke.Type.VIRTUAL, invokedMethod)); @@ -289,13 +285,13 @@ return; } - boolean synchronizedVirtualMethod = method.isSynchronized() && method.isVirtualMethod(); + boolean synchronizedVirtualMethod = definition.isSynchronized() && definition.isVirtualMethod(); feedback.setClassInlinerEligibility( - method, + definition, new ClassInlinerEligibilityInfo( callsReceiver, - new ClassInlinerReceiverAnalysis(appView, method, code).computeReturnsReceiver(), + new ClassInlinerReceiverAnalysis(appView, definition, code).computeReturnsReceiver(), seenMonitor || synchronizedVirtualMethod)); } @@ -345,15 +341,15 @@ return builder.build(); } - private void identifyReturnsArgument( - DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) { + private void identifyReturnsArgument(IRCode code, OptimizationFeedback feedback, Timing timing) { timing.begin("Identify returns argument"); - identifyReturnsArgument(method, code, feedback); + identifyReturnsArgument(code, feedback); timing.end(); } - private void identifyReturnsArgument( - DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) { + private void identifyReturnsArgument(IRCode code, OptimizationFeedback feedback) { + ProgramMethod context = code.context(); + DexEncodedMethod method = context.getDefinition(); List<BasicBlock> normalExits = code.computeNormalExitBlocks(); if (normalExits.isEmpty()) { feedback.methodNeverReturnsNormally(method); @@ -380,7 +376,6 @@ if (definition.isArgument()) { feedback.methodReturnsArgument(method, definition.asArgument().getIndex()); } - DexType context = method.holder(); AbstractValue abstractReturnValue = definition.getAbstractValue(appView, context); if (abstractReturnValue.isNonTrivial()) { feedback.methodReturnsAbstractValue(method, appView, abstractReturnValue); @@ -424,16 +419,9 @@ return; } - DexClass clazz = appView.appInfo().definitionFor(method.holder()); - if (clazz == null) { - assert false; - return; - } - NonTrivialInstanceInitializerInfo.Builder builder = NonTrivialInstanceInitializerInfo.builder(instanceFieldInitializationInfos); - InstanceInitializerInfo instanceInitializerInfo = - analyzeInstanceInitializer(code, clazz, builder); + InstanceInitializerInfo instanceInitializerInfo = analyzeInstanceInitializer(code, builder); feedback.setInstanceInitializerInfo( method, instanceInitializerInfo != null @@ -457,8 +445,9 @@ // // (Note that this initializer does not have to have zero arguments.) private InstanceInitializerInfo analyzeInstanceInitializer( - IRCode code, DexClass clazz, NonTrivialInstanceInitializerInfo.Builder builder) { - if (clazz.definesFinalizer(options.itemFactory)) { + IRCode code, NonTrivialInstanceInitializerInfo.Builder builder) { + ProgramMethod context = code.context(); + if (context.getHolder().definesFinalizer(options.itemFactory)) { // Defining a finalize method can observe the side-effect of Object.<init> GC registration. return null; } @@ -510,7 +499,7 @@ // instructions can trigger class initialization side effects, hence it is not necessary // to mark all fields as potentially being read. Also, none of the instruction types // can cause the receiver to escape. - if (instruction.instructionMayHaveSideEffects(appView, clazz.type)) { + if (instruction.instructionMayHaveSideEffects(appView, context)) { builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); } break; @@ -519,12 +508,13 @@ case STATIC_GET: { FieldInstruction fieldGet = instruction.asFieldInstruction(); - DexEncodedField field = appView.appInfo().resolveField(fieldGet.getField()); + DexEncodedField field = + appView.appInfo().resolveField(fieldGet.getField()).getResolvedField(); if (field == null) { return null; } builder.markFieldAsRead(field); - if (fieldGet.instructionMayHaveSideEffects(appView, clazz.type)) { + if (fieldGet.instructionMayHaveSideEffects(appView, context)) { builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); if (fieldGet.isStaticGet()) { // It could trigger a class initializer. @@ -537,14 +527,15 @@ case INSTANCE_PUT: { InstancePut instancePut = instruction.asInstancePut(); - DexEncodedField field = appView.appInfo().resolveField(instancePut.getField()); + DexEncodedField field = + appView.appInfo().resolveField(instancePut.getField()).getResolvedField(); if (field == null) { return null; } Value object = instancePut.object().getAliasedValue(aliasesThroughAssumeAndCheckCasts); if (object != receiver - || instancePut.instructionInstanceCanThrow(appView, clazz.type).isThrowing()) { + || instancePut.instructionInstanceCanThrow(appView, context).isThrowing()) { builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); } @@ -612,7 +603,7 @@ case INVOKE_NEW_ARRAY: { InvokeNewArray invoke = instruction.asInvokeNewArray(); - if (invoke.instructionMayHaveSideEffects(appView, clazz.type)) { + if (invoke.instructionMayHaveSideEffects(appView, context)) { builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); } for (Value argument : invoke.arguments()) { @@ -644,7 +635,7 @@ case NEW_INSTANCE: { NewInstance newInstance = instruction.asNewInstance(); - if (newInstance.instructionMayHaveSideEffects(appView, clazz.type)) { + if (newInstance.instructionMayHaveSideEffects(appView, context)) { // It could trigger a class initializer. builder .markAllFieldsAsRead() @@ -694,12 +685,12 @@ if (method.isStatic()) { // Identifies if the method preserves class initialization after inlining. feedback.markTriggerClassInitBeforeAnySideEffect( - method, triggersClassInitializationBeforeSideEffect(method.holder(), code, appView)); + method, triggersClassInitializationBeforeSideEffect(code)); } else { // Identifies if the method preserves null check of the receiver after inlining. final Value receiver = code.getThis(); feedback.markCheckNullReceiverBeforeAnySideEffect( - method, receiver.isUsed() && checksNullBeforeSideEffect(code, receiver, appView)); + method, receiver.isUsed() && checksNullBeforeSideEffect(code, receiver)); } } @@ -709,14 +700,17 @@ * * <p>Note: we do not track phis so we may return false negative. This is a conservative approach. */ - private static boolean triggersClassInitializationBeforeSideEffect( - DexType clazz, IRCode code, AppView<?> appView) { + private boolean triggersClassInitializationBeforeSideEffect(IRCode code) { return alwaysTriggerExpectedEffectBeforeAnythingElse( code, (instruction, it) -> { - DexType context = code.method().holder(); + ProgramMethod context = code.context(); if (instruction.definitelyTriggersClassInitialization( - clazz, context, appView, DIRECTLY, AnalysisAssumption.INSTRUCTION_DOES_NOT_THROW)) { + context.getHolderType(), + context, + appView, + DIRECTLY, + AnalysisAssumption.INSTRUCTION_DOES_NOT_THROW)) { // In order to preserve class initialization semantic, the exception must not be caught // by any handler. Therefore, we must ignore this instruction if it is covered by a // catch handler. @@ -726,7 +720,7 @@ // We found an instruction that preserves initialization of the class. return InstructionEffect.DESIRED_EFFECT; } - } else if (instruction.instructionMayHaveSideEffects(appView, clazz)) { + } else if (instruction.instructionMayHaveSideEffects(appView, context)) { // We found a side effect before class initialization. return InstructionEffect.OTHER_EFFECT; } @@ -810,7 +804,7 @@ * * <p>Note: we do not track phis so we may return false negative. This is a conservative approach. */ - private static boolean checksNullBeforeSideEffect(IRCode code, Value value, AppView<?> appView) { + private boolean checksNullBeforeSideEffect(IRCode code, Value value) { return alwaysTriggerExpectedEffectBeforeAnythingElse( code, (instr, it) -> { @@ -847,7 +841,7 @@ if (isInstantiationOfNullPointerException(instr, it, appView.dexItemFactory())) { it.next(); // Skip call to NullPointerException.<init>. return InstructionEffect.NO_EFFECT; - } else if (instr.throwsNpeIfValueIsNull(value, appView, code.method().holder())) { + } else if (instr.throwsNpeIfValueIsNull(value, appView, code.context())) { // In order to preserve NPE semantic, the exception must not be caught by any handler. // Therefore, we must ignore this instruction if it is covered by a catch handler. // Note: this is a conservative approach where we consider that any catch handler could @@ -856,7 +850,7 @@ // We found a NPE check on the value. return InstructionEffect.DESIRED_EFFECT; } - } else if (instr.instructionMayHaveSideEffects(appView, code.method().holder())) { + } else if (instr.instructionMayHaveSideEffects(appView, code.context())) { // If the current instruction is const-string, this could load the parameter name. // Just make sure it is indeed not throwing. if (instr.isConstString() && !instr.instructionInstanceCanThrow()) { @@ -1021,7 +1015,7 @@ if (appView.appInfo().mayHaveSideEffects.containsKey(method.method)) { return; } - DexType context = method.holder(); + ProgramMethod context = code.context(); if (method.isClassInitializer()) { // For class initializers, we also wish to compute if the class initializer has observable // side effects. @@ -1033,9 +1027,9 @@ } else if (classInitializerSideEffect.canBePostponed()) { feedback.classInitializerMayBePostponed(method); } else { - assert !context.isD8R8SynthesizedLambdaClassType() + assert !context.getHolderType().isD8R8SynthesizedLambdaClassType() || options.debug - || appView.appInfo().hasPinnedInstanceInitializer(context) + || appView.appInfo().hasPinnedInstanceInitializer(context.getHolderType()) : "Unexpected observable side effects from lambda `" + context.toSourceString() + "`"; } return; @@ -1044,7 +1038,7 @@ if (method.isSynchronized()) { // If the method is synchronized then it acquires a lock. mayHaveSideEffects = true; - } else if (method.isInstanceInitializer() && hasNonTrivialFinalizeMethod(context)) { + } else if (method.isInstanceInitializer() && hasNonTrivialFinalizeMethod(context.getHolder())) { // If a class T overrides java.lang.Object.finalize(), then treat the constructor as having // side effects. This ensures that we won't remove instructions on the form `new-instance // {v0}, T`. @@ -1064,31 +1058,20 @@ } } - // Returns true if `method` is an initializer and the enclosing class overrides the method - // `void java.lang.Object.finalize()`. - private boolean hasNonTrivialFinalizeMethod(DexType type) { - DexClass clazz = appView.definitionFor(type); - if (clazz != null) { - if (clazz.isProgramClass() && !clazz.isInterface()) { - DexItemFactory dexItemFactory = appView.dexItemFactory(); - ResolutionResult resolutionResult = - appView - .appInfo() - .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMembers.finalize); - - DexEncodedMethod target = resolutionResult.getSingleTarget(); - if (target != null - && target.method != dexItemFactory.enumMethods.finalize - && target.method != dexItemFactory.objectMembers.finalize) { - return true; - } - return false; - } else { - // Conservatively report that the library class could implement finalize(). - return true; - } + // Returns true if the given class overrides the method `void java.lang.Object.finalize()`. + private boolean hasNonTrivialFinalizeMethod(DexProgramClass clazz) { + if (clazz.isInterface()) { + return false; } - return false; + DexItemFactory dexItemFactory = appView.dexItemFactory(); + ResolutionResult resolutionResult = + appView + .appInfo() + .resolveMethodOnClass(appView.dexItemFactory().objectMembers.finalize, clazz); + DexEncodedMethod target = resolutionResult.getSingleTarget(); + return target != null + && target.method != dexItemFactory.enumMethods.finalize + && target.method != dexItemFactory.objectMembers.finalize; } private void computeReturnValueOnlyDependsOnArguments( @@ -1137,7 +1120,7 @@ // invoke-static throwParameterIsNullException(msg) // // or some other variants, e.g., throw null or NPE after the direct null check. - if (argument.isUsed() && checksNullBeforeSideEffect(code, argument, appView)) { + if (argument.isUsed() && checksNullBeforeSideEffect(code, argument)) { paramsCheckedForNull.set(index); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java index 091a5e5..05d9b49 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
@@ -5,21 +5,21 @@ package com.android.tools.r8.ir.optimize.inliner; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.InstancePut; import com.android.tools.r8.ir.code.Instruction; import com.android.tools.r8.ir.code.InvokeDirect; import com.android.tools.r8.ir.code.InvokeMethod; import com.android.tools.r8.ir.optimize.Inliner.Reason; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import java.util.Collection; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import java.util.Set; public abstract class WhyAreYouNotInliningReporter { public static WhyAreYouNotInliningReporter createFor( - DexEncodedMethod callee, AppView<AppInfoWithLiveness> appView, DexEncodedMethod context) { - if (appView.appInfo().whyAreYouNotInlining.contains(callee.method)) { + ProgramMethod callee, AppView<AppInfoWithLiveness> appView, ProgramMethod context) { + if (appView.appInfo().whyAreYouNotInlining.contains(callee.getReference())) { return new WhyAreYouNotInliningReporterImpl( callee, context, appView.options().testing.whyAreYouNotInliningConsumer); } @@ -27,20 +27,20 @@ } public static void handleInvokeWithUnknownTarget( - InvokeMethod invoke, AppView<AppInfoWithLiveness> appView, DexEncodedMethod context) { + InvokeMethod invoke, AppView<AppInfoWithLiveness> appView, ProgramMethod context) { if (appView.appInfo().whyAreYouNotInlining.isEmpty()) { return; } - Collection<DexEncodedMethod> possibleTargets = invoke.lookupTargets(appView, context.holder()); - if (possibleTargets == null) { + ProgramMethodSet possibleProgramTargets = invoke.lookupProgramDispatchTargets(appView, context); + if (possibleProgramTargets == null) { // In principle, this invoke might target any method in the program, but we do not want to // report a message for each of the methods in `AppInfoWithLiveness#whyAreYouNotInlining`, // since that would almost never be useful. return; } - for (DexEncodedMethod possibleTarget : possibleTargets) { + for (ProgramMethod possibleTarget : possibleProgramTargets) { createFor(possibleTarget, appView, context).reportUnknownTarget(); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java index b141817..934651c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.ir.optimize.inliner; -import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.InstancePut; import com.android.tools.r8.ir.code.Instruction; import com.android.tools.r8.ir.code.InvokeDirect; @@ -15,14 +15,14 @@ class WhyAreYouNotInliningReporterImpl extends WhyAreYouNotInliningReporter { - private final DexEncodedMethod callee; - private final DexEncodedMethod context; + private final ProgramMethod callee; + private final ProgramMethod context; private final PrintStream output; private boolean reasonHasBeenReported = false; WhyAreYouNotInliningReporterImpl( - DexEncodedMethod callee, DexEncodedMethod context, PrintStream output) { + ProgramMethod callee, ProgramMethod context, PrintStream output) { this.callee = callee; this.context = context; this.output = output; @@ -30,9 +30,9 @@ private void print(String reason) { output.print("Method `"); - output.print(callee.method.toSourceString()); + output.print(callee.toSourceString()); output.print("` was not inlined into `"); - output.print(context.method.toSourceString()); + output.print(context.toSourceString()); if (reason != null) { output.print("`: "); output.println(reason); @@ -220,7 +220,7 @@ "final field `" + instancePut.getField() + "` must be initialized in a constructor of `" - + callee.holder().toSourceString() + + callee.getHolderType().toSourceString() + "`."); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java index 2a5e9cd..7a81f73 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -157,8 +157,7 @@ DexType holder = invokedMethod.holder; if (lambdaGroup.containsLambda(holder)) { // TODO(b/150685763): Check if we can use simpler lookup. - ResolutionResult resolution = - appView.appInfo().resolveMethod(holder, invokedMethod, false); + ResolutionResult resolution = appView.appInfo().resolveMethodOnClass(invokedMethod); assert resolution.isSingleResolution(); ProgramMethod singleTarget = resolution.asSingleResolution().getResolutionPair().asProgramMethod();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java index 76e81ac..a560844 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
@@ -70,7 +70,7 @@ InvokeMethod invoke, Set<Value> affectedValues) { Value argument = invoke.arguments().get(0); - AbstractValue abstractValue = argument.getAbstractValue(appView, code.method().holder()); + AbstractValue abstractValue = argument.getAbstractValue(appView, code.context()); if (abstractValue.isSingleNumberValue()) { instructionIterator.replaceCurrentInstructionWithStaticGet( appView,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java index 6566187..0c7393b 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexItemFactory.LibraryMembers; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Instruction; @@ -86,12 +87,12 @@ * * <p>In order for library modeling to work in D8, we return a definition for invoke instructions * that are guaranteed to dispatch to a library method in {@link - * InvokeMethod#lookupSingleTarget(AppView, DexType)}. As part of that, we bail-out if the holder - * of the targeted method is not a library class. However, what is usually on the library path - * will be on the program path when compiling the framework itself. To ensure that our library - * modeling works also for the framework compilation, we maintain the set of types that we model, - * and treat these types as library types in {@link InvokeMethod#lookupSingleTarget(AppView, - * DexType)} although they are on the program path. + * InvokeMethod#lookupSingleTarget(AppView, ProgramMethod)}. As part of that, we bail-out if the + * holder of the targeted method is not a library class. However, what is usually on the library + * path will be on the program path when compiling the framework itself. To ensure that our + * library modeling works also for the framework compilation, we maintain the set of types that we + * model, and treat these types as library types in {@link + * InvokeMethod#lookupSingleTarget(AppView, ProgramMethod)} although they are on the program path. */ public boolean isModeled(DexType type) { return modeledLibraryTypes.contains(type); @@ -114,7 +115,7 @@ Instruction instruction = instructionIterator.next(); if (instruction.isInvokeMethod()) { InvokeMethod invoke = instruction.asInvokeMethod(); - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, code.method().holder()); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, code.context()); if (singleTarget != null) { optimizeInvoke(code, instructionIterator, invoke, singleTarget, affectedValues); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java index 1283bf4..64dce88 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.DexItemBasedConstString; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Instruction; @@ -47,7 +48,7 @@ private void optimizeEquals( IRCode code, InstructionListIterator instructionIterator, InvokeMethod invoke) { if (appView.appInfo().hasLiveness()) { - DexType context = code.method().holder(); + ProgramMethod context = code.context(); Value first = invoke.arguments().get(0).getAliasedValue(); Value second = invoke.arguments().get(1).getAliasedValue(); if (isPrunedClassNameComparison(first, second, context) @@ -63,7 +64,7 @@ * has been pruned by the {@link com.android.tools.r8.shaking.Enqueuer}. */ private boolean isPrunedClassNameComparison( - Value classNameValue, Value constStringValue, DexType context) { + Value classNameValue, Value constStringValue, ProgramMethod context) { if (classNameValue.isPhi() || constStringValue.isPhi()) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java index 041cf09..acba57f 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -82,8 +82,8 @@ candidates.put(candidate.type, this); } - boolean isHostClassInitializer(DexEncodedMethod method) { - return factory.isClassConstructor(method.method) && method.holder() == hostType(); + boolean isHostClassInitializer(ProgramMethod method) { + return method.getDefinition().isClassInitializer() && method.getHolderType() == hostType(); } DexType hostType() { @@ -217,10 +217,10 @@ // // NOTE: can be called concurrently. public final void examineMethodCode(IRCode code) { - ProgramMethod method = code.context(); + ProgramMethod context = code.context(); Set<Instruction> alreadyProcessed = Sets.newIdentityHashSet(); - CandidateInfo receiverClassCandidateInfo = candidates.get(method.getHolderType()); + CandidateInfo receiverClassCandidateInfo = candidates.get(context.getHolderType()); Value receiverValue = code.getThis(); // NOTE: is null for static methods. if (receiverClassCandidateInfo != null) { if (receiverValue != null) { @@ -230,26 +230,26 @@ analyzeAllValueUsers( receiverClassCandidateInfo, receiverValue, - factory.isConstructor(method.getReference())); + factory.isConstructor(context.getReference())); // If the candidate is still valid, ignore all instructions // we treat as valid usages on receiver. - if (candidates.get(method.getHolderType()) != null) { + if (candidates.get(context.getHolderType()) != null) { alreadyProcessed.addAll(receiverValue.uniqueUsers()); } } else { // We are inside a static method of candidate class. // Check if this is a valid getter of the singleton field. - if (method.getDefinition().returnType() == method.getHolderType()) { + if (context.getDefinition().returnType() == context.getHolderType()) { List<Instruction> examined = isValidGetter(receiverClassCandidateInfo, code); if (examined != null) { DexEncodedMethod getter = receiverClassCandidateInfo.getter.get(); if (getter == null) { - receiverClassCandidateInfo.getter.set(method.getDefinition()); + receiverClassCandidateInfo.getter.set(context.getDefinition()); // Except for static-get and return, iterate other remaining instructions if any. alreadyProcessed.addAll(examined); } else { - assert getter != method.getDefinition(); + assert getter != context.getDefinition(); // Not sure how to deal with many getters. receiverClassCandidateInfo.invalidate(); } @@ -275,8 +275,7 @@ if (instruction.isNewInstance()) { // Check the class being initialized against valid staticizing candidates. NewInstance newInstance = instruction.asNewInstance(); - CandidateInfo candidateInfo = - processInstantiation(method.getDefinition(), iterator, newInstance); + CandidateInfo candidateInfo = processInstantiation(context, iterator, newInstance); if (candidateInfo != null) { alreadyProcessed.addAll(newInstance.outValue().aliasedUsers()); // For host class initializers having eligible instantiation we also want to @@ -284,7 +283,7 @@ // This must guarantee that removing field access will not result in missing side // effects, otherwise we can still staticize, but cannot remove singleton reads. while (iterator.hasNext()) { - if (!isAllowedInHostClassInitializer(method.getHolderType(), iterator.next(), code)) { + if (!isAllowedInHostClassInitializer(context.getHolderType(), iterator.next(), code)) { candidateInfo.preserveRead.set(true); iterator.previous(); break; @@ -293,7 +292,7 @@ } referencedFrom .computeIfAbsent(candidateInfo, ignore -> new LongLivedProgramMethodSetBuilder()) - .add(method); + .add(context); } continue; } @@ -315,7 +314,7 @@ if (info != null) { referencedFrom .computeIfAbsent(info, ignore -> new LongLivedProgramMethodSetBuilder()) - .add(method); + .add(context); // If the candidate is still valid, ignore all usages in further analysis. Value value = instruction.outValue(); if (value != null) { @@ -331,7 +330,7 @@ if (info != null) { referencedFrom .computeIfAbsent(info, ignore -> new LongLivedProgramMethodSetBuilder()) - .add(method); + .add(context); // If the candidate is still valid, ignore all usages in further analysis. Value value = instruction.outValue(); if (value != null) { @@ -380,8 +379,7 @@ } private CandidateInfo processInstantiation( - DexEncodedMethod method, ListIterator<Instruction> iterator, NewInstance newInstance) { - + ProgramMethod context, ListIterator<Instruction> iterator, NewInstance newInstance) { DexType candidateType = newInstance.clazz; CandidateInfo candidateInfo = candidates.get(candidateType); if (candidateInfo == null) { @@ -393,7 +391,7 @@ return candidateInfo.invalidate(); } - if (!candidateInfo.isHostClassInitializer(method)) { + if (!candidateInfo.isHostClassInitializer(context)) { // A valid candidate must only have one instantiation which is // done in the static initializer of the host class. return candidateInfo.invalidate(); @@ -445,7 +443,7 @@ } Set<Instruction> users = SetUtils.newIdentityHashSet(candidateValue.uniqueUsers()); Instruction constructorCall = iterator.next(); - if (!isValidInitCall(candidateInfo, constructorCall, candidateValue, candidateType)) { + if (!isValidInitCall(candidateInfo, constructorCall, candidateValue, context)) { iterator.previous(); return candidateInfo.invalidate(); } @@ -475,7 +473,7 @@ } private boolean isValidInitCall( - CandidateInfo info, Instruction instruction, Value candidateValue, DexType candidateType) { + CandidateInfo info, Instruction instruction, Value candidateValue, ProgramMethod context) { if (!instruction.isInvokeDirect()) { return false; } @@ -483,12 +481,12 @@ // Check constructor. InvokeDirect invoke = instruction.asInvokeDirect(); DexEncodedMethod methodInvoked = - appView.appInfo().lookupDirectTarget(invoke.getInvokedMethod(), info.candidate); + appView.appInfo().lookupDirectTarget(invoke.getInvokedMethod(), context); List<Value> values = invoke.inValues(); if (ListUtils.lastIndexMatching(values, v -> v.getAliasedValue() == candidateValue) != 0 || methodInvoked == null - || methodInvoked.holder() != candidateType) { + || methodInvoked.holder() != info.candidate.type) { return false; } @@ -511,8 +509,7 @@ } // Allow single assignment to a singleton field. StaticPut staticPut = instruction.asStaticPut(); - DexEncodedField fieldAccessed = - appView.appInfo().lookupStaticTarget(staticPut.getField().holder, staticPut.getField()); + DexEncodedField fieldAccessed = appView.appInfo().lookupStaticTarget(staticPut.getField()); return fieldAccessed == info.singletonField; } @@ -529,8 +526,7 @@ for (Instruction instr : code.instructions()) { if (instr.isStaticGet()) { staticGet = instr.asStaticGet(); - DexEncodedField fieldAccessed = - appView.appInfo().lookupStaticTarget(staticGet.getField().holder, staticGet.getField()); + DexEncodedField fieldAccessed = appView.appInfo().lookupStaticTarget(staticGet.getField()); if (fieldAccessed != info.singletonField) { return null; } @@ -562,7 +558,7 @@ return null; } - assert candidateInfo.singletonField == appView.appInfo().lookupStaticTarget(field.holder, field) + assert candidateInfo.singletonField == appView.appInfo().lookupStaticTarget(field) : "Added reference after collectCandidates(...)?"; Value singletonValue = staticGet.dest(); @@ -651,7 +647,7 @@ } AppInfoWithLiveness appInfo = appView.appInfo(); ResolutionResult resolutionResult = - appInfo.resolveMethod(methodReferenced.holder, methodReferenced); + appInfo.unsafeResolveMethodDueToDexFormat(methodReferenced); DexEncodedMethod methodInvoked = user.isInvokeDirect() ? resolutionResult.lookupInvokeDirectTarget(candidateInfo.candidate, appInfo)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java index 07d330b..53122b0 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
@@ -11,6 +11,7 @@ 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.ProgramMethod; import com.android.tools.r8.ir.analysis.escape.EscapeAnalysis; import com.android.tools.r8.ir.analysis.escape.EscapeAnalysisConfiguration; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; @@ -882,7 +883,7 @@ AppView<?> appView, EscapeAnalysis escapeAnalysis, Instruction escapeRoute, - DexMethod context) { + ProgramMethod context) { if (escapeRoute.isReturn() || escapeRoute.isThrow() || escapeRoute.isStaticPut()) { logEscapingRoute(false); return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java index ae94194..d00100a 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -17,6 +17,7 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.escape.EscapeAnalysis; import com.android.tools.r8.ir.analysis.escape.EscapeAnalysisConfiguration; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; @@ -589,7 +590,7 @@ AppView<?> appView, EscapeAnalysis escapeAnalysis, Instruction escapeRoute, - DexMethod context) { + ProgramMethod context) { if (escapeRoute.isReturn() || escapeRoute.isThrow() || escapeRoute.isStaticPut()) { return false; }
diff --git a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java index 18b3533..b225440 100644 --- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java +++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.kotlin; -import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; @@ -192,9 +190,4 @@ public final DexMethod throwNpe = factory.createMethod( type, factory.createProto(factory.voidType), "throwNpe"); } - - // Calculates kotlin info for a class. - public KotlinClassLevelInfo getKotlinInfo(DexClass clazz, AppView<?> appView) { - return KotlinClassMetadataReader.getKotlinInfo(this, clazz, appView); - } }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java index 47ed582..a4bc5b0 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -4,7 +4,10 @@ package com.android.tools.r8.kotlin; +import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromBinaryName; + import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.naming.NamingLens; @@ -31,19 +34,21 @@ this.arguments = arguments; } - private static KotlinAnnotationInfo create(KmAnnotation annotation, AppView<?> appView) { - String descriptor = DescriptorUtils.getDescriptorFromClassBinaryName(annotation.getClassName()); - DexType type = appView.dexItemFactory().createType(descriptor); - return new KotlinAnnotationInfo(type, annotation.getArguments()); + private static KotlinAnnotationInfo create( + KmAnnotation annotation, DexDefinitionSupplier definitionSupplier) { + return new KotlinAnnotationInfo( + referenceTypeFromBinaryName(annotation.getClassName(), definitionSupplier), + annotation.getArguments()); } - static List<KotlinAnnotationInfo> create(List<KmAnnotation> annotations, AppView<?> appView) { + static List<KotlinAnnotationInfo> create( + List<KmAnnotation> annotations, DexDefinitionSupplier definitionSupplier) { if (annotations.isEmpty()) { return EMPTY_ANNOTATIONS; } ImmutableList.Builder<KotlinAnnotationInfo> builder = ImmutableList.builder(); for (KmAnnotation annotation : annotations) { - builder.add(create(annotation, appView)); + builder.add(create(annotation, definitionSupplier)); } return builder.build(); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java index b2f71cb..2cb8fe4 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -4,11 +4,13 @@ package com.android.tools.r8.kotlin; +import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromBinaryName; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toJvmFieldSignature; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toJvmMethodSignature; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexString; @@ -16,6 +18,7 @@ import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.Reporter; import com.google.common.collect.ImmutableList; import java.util.HashMap; import java.util.List; @@ -68,7 +71,11 @@ this.anonymousObjectOrigin = anonymousObjectOrigin; } - public static KotlinClassInfo create(KmClass kmClass, DexClass hostClass, AppView<?> appView) { + public static KotlinClassInfo create( + KmClass kmClass, + DexClass hostClass, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { Map<String, DexEncodedField> fieldMap = new HashMap<>(); for (DexEncodedField field : hostClass.fields()) { fieldMap.put(toJvmFieldSignature(field.field).asString(), field); @@ -79,7 +86,8 @@ } ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder(); for (KmConstructor kmConstructor : kmClass.getConstructors()) { - KotlinConstructorInfo constructorInfo = KotlinConstructorInfo.create(kmConstructor, appView); + KotlinConstructorInfo constructorInfo = + KotlinConstructorInfo.create(kmConstructor, definitionSupplier, reporter); JvmMethodSignature signature = JvmExtensionsKt.getSignature(kmConstructor); if (signature != null) { DexEncodedMethod method = methodMap.get(signature.asString()); @@ -92,72 +100,65 @@ notBackedConstructors.add(constructorInfo); } KotlinDeclarationContainerInfo container = - KotlinDeclarationContainerInfo.create(kmClass, methodMap, fieldMap, appView); - setCompanionObject(kmClass, hostClass, appView); + KotlinDeclarationContainerInfo.create( + kmClass, methodMap, fieldMap, definitionSupplier, reporter); + setCompanionObject(kmClass, hostClass, reporter); return new KotlinClassInfo( kmClass.getFlags(), kmClass.name, JvmExtensionsKt.getModuleName(kmClass), container, - KotlinTypeParameterInfo.create(kmClass.getTypeParameters(), appView), + KotlinTypeParameterInfo.create(kmClass.getTypeParameters(), definitionSupplier, reporter), notBackedConstructors.build(), - getSuperTypes(kmClass.getSupertypes(), appView), - getSealedSubClasses(hostClass, kmClass.getSealedSubclasses(), appView), - getNestedClasses(hostClass, kmClass.getNestedClasses(), appView), + getSuperTypes(kmClass.getSupertypes(), definitionSupplier, reporter), + getSealedSubClasses(hostClass, kmClass.getSealedSubclasses(), definitionSupplier), + getNestedClasses(hostClass, kmClass.getNestedClasses(), definitionSupplier), kmClass.getEnumEntries(), - getAnonymousObjectOrigin(kmClass, appView)); + getAnonymousObjectOrigin(kmClass, definitionSupplier)); } - private static DexType getAnonymousObjectOrigin(KmClass kmClass, AppView<?> appView) { + private static DexType getAnonymousObjectOrigin( + KmClass kmClass, DexDefinitionSupplier definitionSupplier) { String anonymousObjectOriginName = JvmExtensionsKt.getAnonymousObjectOriginName(kmClass); if (anonymousObjectOriginName != null) { - return appView - .dexItemFactory() - .createType(DescriptorUtils.getDescriptorFromClassBinaryName(anonymousObjectOriginName)); + return referenceTypeFromBinaryName(anonymousObjectOriginName, definitionSupplier); } return null; } private static List<DexType> getNestedClasses( - DexClass clazz, List<String> nestedClasses, AppView<?> appView) { + DexClass clazz, List<String> nestedClasses, DexDefinitionSupplier definitionSupplier) { ImmutableList.Builder<DexType> nestedTypes = ImmutableList.builder(); for (String nestedClass : nestedClasses) { String binaryName = clazz.type.toBinaryName() + DescriptorUtils.INNER_CLASS_SEPARATOR + nestedClass; - DexType nestedType = - appView - .dexItemFactory() - .createType(DescriptorUtils.getDescriptorFromClassBinaryName(binaryName)); - nestedTypes.add(nestedType); + nestedTypes.add(referenceTypeFromBinaryName(binaryName, definitionSupplier)); } return nestedTypes.build(); } private static List<DexType> getSealedSubClasses( - DexClass clazz, List<String> sealedSubclasses, AppView<?> appView) { + DexClass clazz, List<String> sealedSubclasses, DexDefinitionSupplier definitionSupplier) { ImmutableList.Builder<DexType> sealedTypes = ImmutableList.builder(); for (String sealedSubClass : sealedSubclasses) { String binaryName = sealedSubClass.replace( DescriptorUtils.JAVA_PACKAGE_SEPARATOR, DescriptorUtils.INNER_CLASS_SEPARATOR); - DexType sealedType = - appView - .dexItemFactory() - .createType(DescriptorUtils.getDescriptorFromClassBinaryName(binaryName)); - sealedTypes.add(sealedType); + sealedTypes.add(referenceTypeFromBinaryName(binaryName, definitionSupplier)); } return sealedTypes.build(); } - private static List<KotlinTypeInfo> getSuperTypes(List<KmType> superTypes, AppView<?> appView) { + private static List<KotlinTypeInfo> getSuperTypes( + List<KmType> superTypes, DexDefinitionSupplier definitionSupplier, Reporter reporter) { ImmutableList.Builder<KotlinTypeInfo> superTypeInfos = ImmutableList.builder(); for (KmType superType : superTypes) { - superTypeInfos.add(KotlinTypeInfo.create(superType, appView)); + superTypeInfos.add(KotlinTypeInfo.create(superType, definitionSupplier, reporter)); } return superTypeInfos.build(); } - private static void setCompanionObject(KmClass kmClass, DexClass hostClass, AppView<?> appView) { + private static void setCompanionObject(KmClass kmClass, DexClass hostClass, Reporter reporter) { String companionObjectName = kmClass.getCompanionObject(); if (companionObjectName == null) { return; @@ -168,10 +169,8 @@ return; } } - appView - .options() - .reporter - .warning(KotlinMetadataDiagnostic.missingCompanionObject(hostClass, companionObjectName)); + reporter.warning( + KotlinMetadataDiagnostic.missingCompanionObject(hostClass, companionObjectName)); } @Override @@ -235,7 +234,7 @@ } // Rewrite nested classes. for (DexType nestedClass : nestedClasses) { - if (appView.definitionFor(nestedClass) != null) { + if (appView.appInfo().isNonProgramTypeOrLiveProgramType(nestedClass)) { String descriptor = KotlinMetadataUtils.kotlinNameFromDescriptor(namingLens.lookupDescriptor(nestedClass)); // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz is the @@ -246,7 +245,7 @@ } // Rewrite sealed sub classes. for (DexType sealedSubClass : sealedSubClasses) { - if (appView.definitionFor(sealedSubClass) != null) { + if (appView.appInfo().isNonProgramTypeOrLiveProgramType(sealedSubClass)) { String descriptor = KotlinMetadataUtils.kotlinNameFromDescriptor( namingLens.lookupDescriptor(sealedSubClass));
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java index 13ae5f5..f52f65e 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -5,14 +5,15 @@ import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO; -import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexAnnotation; import com.android.tools.r8.graph.DexAnnotationElement; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedAnnotation; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexValue; import com.android.tools.r8.graph.DexValue.DexValueArray; +import com.android.tools.r8.utils.Reporter; import com.android.tools.r8.utils.StringDiagnostic; import java.util.IdentityHashMap; import java.util.Map; @@ -23,31 +24,25 @@ public final class KotlinClassMetadataReader { public static KotlinClassLevelInfo getKotlinInfo( - Kotlin kotlin, DexClass clazz, AppView<?> appView) { + Kotlin kotlin, DexClass clazz, DexDefinitionSupplier definitionSupplier, Reporter reporter) { DexAnnotation meta = clazz.annotations().getFirstMatching(kotlin.metadata.kotlinMetadataType); if (meta != null) { try { - return createKotlinInfo(kotlin, clazz, meta.annotation, appView); + return createKotlinInfo(kotlin, clazz, meta.annotation, definitionSupplier, reporter); } catch (ClassCastException | InconsistentKotlinMetadataException | MetadataError e) { - appView - .options() - .reporter - .info( - new StringDiagnostic( - "Class " - + clazz.type.toSourceString() - + " has malformed kotlin.Metadata: " - + e.getMessage())); + reporter.info( + new StringDiagnostic( + "Class " + + clazz.type.toSourceString() + + " has malformed kotlin.Metadata: " + + e.getMessage())); } catch (Throwable e) { - appView - .options() - .reporter - .info( - new StringDiagnostic( - "Unexpected error while reading " - + clazz.type.toSourceString() - + "'s kotlin.Metadata: " - + e.getMessage())); + reporter.info( + new StringDiagnostic( + "Unexpected error while reading " + + clazz.type.toSourceString() + + "'s kotlin.Metadata: " + + e.getMessage())); } } return NO_KOTLIN_INFO; @@ -85,27 +80,35 @@ } public static KotlinClassLevelInfo createKotlinInfo( - Kotlin kotlin, DexClass clazz, DexEncodedAnnotation metadataAnnotation, AppView<?> appView) { + Kotlin kotlin, + DexClass clazz, + DexEncodedAnnotation metadataAnnotation, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, metadataAnnotation); if (kMetadata instanceof KotlinClassMetadata.Class) { return KotlinClassInfo.create( - ((KotlinClassMetadata.Class) kMetadata).toKmClass(), clazz, appView); + ((KotlinClassMetadata.Class) kMetadata).toKmClass(), clazz, definitionSupplier, reporter); } else if (kMetadata instanceof KotlinClassMetadata.FileFacade) { // e.g., B.kt becomes class `BKt` return KotlinFileFacadeInfo.create( - (KotlinClassMetadata.FileFacade) kMetadata, clazz, appView); + (KotlinClassMetadata.FileFacade) kMetadata, clazz, definitionSupplier, reporter); } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassFacade) { // multi-file class with the same @JvmName. return KotlinMultiFileClassFacadeInfo.create( - (KotlinClassMetadata.MultiFileClassFacade) kMetadata, appView); + (KotlinClassMetadata.MultiFileClassFacade) kMetadata, definitionSupplier); } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassPart) { // A single file, which is part of multi-file class. return KotlinMultiFileClassPartInfo.create( - (KotlinClassMetadata.MultiFileClassPart) kMetadata, clazz, appView); + (KotlinClassMetadata.MultiFileClassPart) kMetadata, clazz, definitionSupplier, reporter); } else if (kMetadata instanceof KotlinClassMetadata.SyntheticClass) { return KotlinSyntheticClassInfo.create( - (KotlinClassMetadata.SyntheticClass) kMetadata, clazz, kotlin, appView); + (KotlinClassMetadata.SyntheticClass) kMetadata, + clazz, + kotlin, + definitionSupplier, + reporter); } else { throw new MetadataError("unsupported 'k' value: " + kMetadata.getHeader().getKind()); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java index 86db718..60851e2 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -4,13 +4,17 @@ package com.android.tools.r8.kotlin; +import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromDescriptor; + import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.Reporter; import kotlinx.metadata.KmClassifier; import kotlinx.metadata.KmClassifier.TypeAlias; import kotlinx.metadata.KmClassifier.TypeParameter; @@ -18,7 +22,8 @@ public abstract class KotlinClassifierInfo { - public static KotlinClassifierInfo create(KmClassifier classifier, AppView<?> appView) { + public static KotlinClassifierInfo create( + KmClassifier classifier, DexDefinitionSupplier definitionSupplier, Reporter reporter) { if (classifier instanceof KmClassifier.Class) { String typeName = ((KmClassifier.Class) classifier).getName(); // If this name starts with '.', it represents a local class or an anonymous object. This is @@ -29,8 +34,8 @@ } String descriptor = DescriptorUtils.getDescriptorFromKotlinClassifier(typeName); if (DescriptorUtils.isClassDescriptor(descriptor)) { - DexType type = appView.dexItemFactory().createType(descriptor); - return new KotlinClassClassifierInfo(type); + return new KotlinClassClassifierInfo( + referenceTypeFromDescriptor(descriptor, definitionSupplier)); } else { return new KotlinUnknownClassClassifierInfo(typeName); } @@ -39,10 +44,7 @@ } else if (classifier instanceof KmClassifier.TypeParameter) { return new KotlinTypeParameterClassifierInfo(((TypeParameter) classifier).getId()); } else { - appView - .options() - .reporter - .warning(KotlinMetadataDiagnostic.unknownClassifier(classifier.toString())); + reporter.warning(KotlinMetadataDiagnostic.unknownClassifier(classifier.toString())); return new KotlinUnknownClassifierInfo(classifier.toString()); } }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java index 3e9ee04..6f9f366 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
@@ -5,9 +5,11 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import java.util.List; import kotlinx.metadata.KmClass; import kotlinx.metadata.KmConstructor; @@ -32,11 +34,14 @@ this.signature = signature; } - public static KotlinConstructorInfo create(KmConstructor kmConstructor, AppView<?> appView) { + public static KotlinConstructorInfo create( + KmConstructor kmConstructor, DexDefinitionSupplier definitionSupplier, Reporter reporter) { return new KotlinConstructorInfo( kmConstructor.getFlags(), - KotlinValueParameterInfo.create(kmConstructor.getValueParameters(), appView), - KotlinJvmMethodSignatureInfo.create(JvmExtensionsKt.getSignature(kmConstructor), appView)); + KotlinValueParameterInfo.create( + kmConstructor.getValueParameters(), definitionSupplier, reporter), + KotlinJvmMethodSignatureInfo.create( + JvmExtensionsKt.getSignature(kmConstructor), definitionSupplier)); } public void rewrite(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java index d1b2913..6dc4d4a 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -8,11 +8,13 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.kotlin.KotlinMetadataUtils.KmPropertyProcessor; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import com.google.common.collect.ImmutableList; import java.util.IdentityHashMap; import java.util.List; @@ -47,7 +49,8 @@ KmDeclarationContainer container, Map<String, DexEncodedMethod> methodSignatureMap, Map<String, DexEncodedField> fieldSignatureMap, - AppView<?> appView) { + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { ImmutableList.Builder<KotlinFunctionInfo> notBackedFunctions = ImmutableList.builder(); for (KmFunction kmFunction : container.getFunctions()) { JvmMethodSignature signature = JvmExtensionsKt.getSignature(kmFunction); @@ -55,7 +58,8 @@ assert false; continue; } - KotlinFunctionInfo kotlinFunctionInfo = KotlinFunctionInfo.create(kmFunction, appView); + KotlinFunctionInfo kotlinFunctionInfo = + KotlinFunctionInfo.create(kmFunction, definitionSupplier, reporter); DexEncodedMethod method = methodSignatureMap.get(signature.asString()); if (method == null) { notBackedFunctions.add(kotlinFunctionInfo); @@ -76,7 +80,8 @@ ImmutableList.Builder<KotlinPropertyInfo> notBackedProperties = ImmutableList.builder(); for (KmProperty kmProperty : container.getProperties()) { - KotlinPropertyInfo kotlinPropertyInfo = KotlinPropertyInfo.create(kmProperty, appView); + KotlinPropertyInfo kotlinPropertyInfo = + KotlinPropertyInfo.create(kmProperty, definitionSupplier, reporter); KmPropertyProcessor propertyProcessor = new KmPropertyProcessor(kmProperty); boolean hasBacking = false; if (propertyProcessor.fieldSignature() != null) { @@ -108,16 +113,16 @@ } } return new KotlinDeclarationContainerInfo( - getTypeAliases(container.getTypeAliases(), appView), + getTypeAliases(container.getTypeAliases(), definitionSupplier, reporter), notBackedFunctions.build(), notBackedProperties.build()); } private static List<KotlinTypeAliasInfo> getTypeAliases( - List<KmTypeAlias> aliases, AppView<?> appView) { + List<KmTypeAlias> aliases, DexDefinitionSupplier definitionSupplier, Reporter reporter) { ImmutableList.Builder<KotlinTypeAliasInfo> builder = ImmutableList.builder(); for (KmTypeAlias alias : aliases) { - builder.add(KotlinTypeAliasInfo.create(alias, appView)); + builder.add(KotlinTypeAliasInfo.create(alias, definitionSupplier, reporter)); } return builder.build(); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java index ee2f81d..ccd957a 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
@@ -6,8 +6,10 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import kotlinx.metadata.KmPackage; import kotlinx.metadata.jvm.KotlinClassHeader; import kotlinx.metadata.jvm.KotlinClassMetadata; @@ -23,9 +25,12 @@ } public static KotlinFileFacadeInfo create( - FileFacade kmFileFacade, DexClass clazz, AppView<?> appView) { + FileFacade kmFileFacade, + DexClass clazz, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { return new KotlinFileFacadeInfo( - KotlinPackageInfo.create(kmFileFacade.toKmPackage(), clazz, appView)); + KotlinPackageInfo.create(kmFileFacade.toKmPackage(), clazz, definitionSupplier, reporter)); } @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java index c1170a1..58b07cb 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -4,12 +4,15 @@ package com.android.tools.r8.kotlin; +import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromBinaryName; + import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.Reporter; import java.util.List; import kotlinx.metadata.KmFunction; import kotlinx.metadata.KmFunctionVisitor; @@ -54,24 +57,27 @@ this.lambdaClassOrigin = lambdaClassOrigin; } - static KotlinFunctionInfo create(KmFunction kmFunction, AppView<?> appView) { + static KotlinFunctionInfo create( + KmFunction kmFunction, DexDefinitionSupplier definitionSupplier, Reporter reporter) { return new KotlinFunctionInfo( kmFunction.getFlags(), kmFunction.getName(), - KotlinTypeInfo.create(kmFunction.getReturnType(), appView), - KotlinTypeInfo.create(kmFunction.getReceiverParameterType(), appView), - KotlinValueParameterInfo.create(kmFunction.getValueParameters(), appView), - KotlinTypeParameterInfo.create(kmFunction.getTypeParameters(), appView), - KotlinJvmMethodSignatureInfo.create(JvmExtensionsKt.getSignature(kmFunction), appView), - getlambdaClassOrigin(kmFunction, appView)); + KotlinTypeInfo.create(kmFunction.getReturnType(), definitionSupplier, reporter), + KotlinTypeInfo.create(kmFunction.getReceiverParameterType(), definitionSupplier, reporter), + KotlinValueParameterInfo.create( + kmFunction.getValueParameters(), definitionSupplier, reporter), + KotlinTypeParameterInfo.create( + kmFunction.getTypeParameters(), definitionSupplier, reporter), + KotlinJvmMethodSignatureInfo.create( + JvmExtensionsKt.getSignature(kmFunction), definitionSupplier), + getlambdaClassOrigin(kmFunction, definitionSupplier)); } - private static DexType getlambdaClassOrigin(KmFunction kmFunction, AppView<?> appView) { + private static DexType getlambdaClassOrigin( + KmFunction kmFunction, DexDefinitionSupplier definitionSupplier) { String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction); if (lambdaClassOriginName != null) { - return appView - .dexItemFactory() - .createType(DescriptorUtils.getDescriptorFromClassBinaryName(lambdaClassOriginName)); + return referenceTypeFromBinaryName(lambdaClassOriginName, definitionSupplier); } return null; }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinInfoCollector.java b/src/main/java/com/android/tools/r8/kotlin/KotlinInfoCollector.java deleted file mode 100644 index 94f9b12..0000000 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinInfoCollector.java +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (c) 2020, 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.kotlin; - -import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexApplication; -import com.android.tools.r8.utils.ThreadUtils; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; - -public class KotlinInfoCollector { - public static void computeKotlinInfoForProgramClasses( - DexApplication application, AppView<?> appView, ExecutorService executorService) - throws ExecutionException { - if (appView.options().kotlinOptimizationOptions().disableKotlinSpecificOptimizations) { - return; - } - Kotlin kotlin = appView.dexItemFactory().kotlin; - ThreadUtils.processItems( - application.classes(), - programClass -> { - programClass.setKotlinInfo(kotlin.getKotlinInfo(programClass, appView)); - }, - executorService); - } -}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java index 0dae9cf..69c0442 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
@@ -4,9 +4,11 @@ package com.android.tools.r8.kotlin; +import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromDescriptor; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toRenamedDescriptorOrDefault; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.naming.NamingLens; @@ -28,12 +30,13 @@ } public static KotlinJvmFieldSignatureInfo create( - JvmFieldSignature fieldSignature, AppView<?> appView) { + JvmFieldSignature fieldSignature, DexDefinitionSupplier definitionSupplier) { if (fieldSignature == null) { return null; } return new KotlinJvmFieldSignatureInfo( - fieldSignature.getName(), appView.dexItemFactory().createType(fieldSignature.getDesc())); + fieldSignature.getName(), + referenceTypeFromDescriptor(fieldSignature.getDesc(), definitionSupplier)); } public JvmFieldSignature rewrite(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java index 354364a..d9d5c9d 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
@@ -4,11 +4,12 @@ package com.android.tools.r8.kotlin; +import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromDescriptor; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toRenamedDescriptorOrDefault; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; @@ -36,14 +37,13 @@ } public static KotlinJvmMethodSignatureInfo create( - JvmMethodSignature methodSignature, AppView<?> appView) { + JvmMethodSignature methodSignature, DexDefinitionSupplier definitionSupplier) { if (methodSignature == null) { return null; } String kotlinDescriptor = methodSignature.getDesc(); String returnTypeDescriptor = DescriptorUtils.getReturnTypeDescriptor(kotlinDescriptor); - DexItemFactory factory = appView.dexItemFactory(); - DexType returnType = factory.createType(returnTypeDescriptor); + DexType returnType = referenceTypeFromDescriptor(returnTypeDescriptor, definitionSupplier); String[] descriptors = DescriptorUtils.getArgumentTypeDescriptors(kotlinDescriptor); if (descriptors.length == 0) { return new KotlinJvmMethodSignatureInfo( @@ -51,7 +51,7 @@ } ImmutableList.Builder<DexType> parameters = ImmutableList.builder(); for (String descriptor : descriptors) { - parameters.add(factory.createType(descriptor)); + parameters.add(referenceTypeFromDescriptor(descriptor, definitionSupplier)); } return new KotlinJvmMethodSignatureInfo( methodSignature.getName(), returnType, parameters.build());
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java index 107d197..d25f105 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
@@ -8,9 +8,11 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import kotlinx.metadata.KmLambda; import kotlinx.metadata.KmLambdaVisitor; import kotlinx.metadata.jvm.JvmExtensionsKt; @@ -25,7 +27,11 @@ this.function = function; } - static KotlinLambdaInfo create(DexClass clazz, KmLambda lambda, AppView<?> appView) { + static KotlinLambdaInfo create( + DexClass clazz, + KmLambda lambda, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { if (lambda == null) { assert false; return null; @@ -37,7 +43,8 @@ } for (DexEncodedMethod method : clazz.methods()) { if (toJvmMethodSignature(method.method).asString().equals(signature.asString())) { - KotlinFunctionInfo kotlinFunctionInfo = KotlinFunctionInfo.create(lambda.function, appView); + KotlinFunctionInfo kotlinFunctionInfo = + KotlinFunctionInfo.create(lambda.function, definitionSupplier, reporter); method.setKotlinMemberInfo(kotlinFunctionInfo); return new KotlinLambdaInfo(kotlinFunctionInfo); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java new file mode 100644 index 0000000..d280d134 --- /dev/null +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -0,0 +1,29 @@ +// Copyright (c) 2020, 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.kotlin; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.analysis.EnqueuerAnalysis; +import com.android.tools.r8.shaking.EnqueuerWorklist; + +public class KotlinMetadataEnqueuerExtension extends EnqueuerAnalysis { + + private final AppView<?> appView; + + public KotlinMetadataEnqueuerExtension(AppView<?> appView) { + this.appView = appView; + } + + @Override + public void processNewlyLiveClass( + DexProgramClass clazz, EnqueuerWorklist worklist, DexDefinitionSupplier definitionSupplier) { + Kotlin kotlin = appView.dexItemFactory().kotlin; + clazz.setKotlinInfo( + KotlinClassMetadataReader.getKotlinInfo( + kotlin, clazz, definitionSupplier, appView.options().reporter)); + } +}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java index b3e0eb4..b3c167f 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -67,8 +67,6 @@ } public void run(ExecutorService executorService) throws ExecutionException { - // TODO(b/152283077): Don't disable the assert. - appView.appInfo().disableDefinitionForAssert(); ThreadUtils.processItems( appView.appInfo().classes(), clazz -> { @@ -95,7 +93,6 @@ } }, executorService); - appView.appInfo().enableDefinitionForAssert(); } private DexAnnotation createKotlinMetadataAnnotation(KotlinClassHeader header) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java index 277201c..fb173a2 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -8,6 +8,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexString; @@ -132,4 +133,20 @@ static String kotlinNameFromDescriptor(DexString descriptor) { return DescriptorUtils.getBinaryNameFromDescriptor(descriptor.toString()); } + + static DexType referenceTypeFromBinaryName( + String binaryName, DexDefinitionSupplier definitionSupplier) { + return referenceTypeFromDescriptor( + DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), definitionSupplier); + } + + static DexType referenceTypeFromDescriptor( + String descriptor, DexDefinitionSupplier definitionSupplier) { + DexType type = definitionSupplier.dexItemFactory().createType(descriptor); + // Lookup the definition, ignoring the result. This populates the sets in the Enqueuer. + if (type.isClassType()) { + definitionSupplier.definitionFor(type); + } + return type; + } }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java index 02efea2..7eaa6b8 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -6,6 +6,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.naming.NamingLens; @@ -28,7 +29,7 @@ } static KotlinMultiFileClassFacadeInfo create( - MultiFileClassFacade kmMultiFileClassFacade, AppView<?> appView) { + MultiFileClassFacade kmMultiFileClassFacade, DexDefinitionSupplier appView) { ImmutableList.Builder<DexType> builder = ImmutableList.builder(); for (String partClassName : kmMultiFileClassFacade.getPartClassNames()) { String descriptor = DescriptorUtils.getDescriptorFromClassBinaryName(partClassName); @@ -55,7 +56,7 @@ new KotlinClassMetadata.MultiFileClassFacade.Writer(); List<String> partClassNameStrings = new ArrayList<>(partClassNames.size()); for (DexType partClassName : partClassNames) { - if (appView.definitionFor(partClassName) != null) { + if (appView.appInfo().isNonProgramTypeOrLiveProgramType(partClassName)) { DexString descriptor = namingLens.lookupDescriptor(partClassName); String classifier = DescriptorUtils.descriptorToKotlinClassifier(descriptor.toString()); partClassNameStrings.add(classifier);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java index 69ea8e4..6a06b7d 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
@@ -6,8 +6,10 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import kotlinx.metadata.KmPackage; import kotlinx.metadata.jvm.KotlinClassHeader; import kotlinx.metadata.jvm.KotlinClassMetadata; @@ -25,10 +27,13 @@ } static KotlinMultiFileClassPartInfo create( - MultiFileClassPart classPart, DexClass clazz, AppView<?> appView) { + MultiFileClassPart classPart, + DexClass clazz, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { return new KotlinMultiFileClassPartInfo( classPart.getFacadeClassName(), - KotlinPackageInfo.create(classPart.toKmPackage(), clazz, appView)); + KotlinPackageInfo.create(classPart.toKmPackage(), clazz, definitionSupplier, reporter)); } @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java index c90d673..7a667e6 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -9,10 +9,12 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import java.util.HashMap; import java.util.Map; import kotlinx.metadata.KmPackage; @@ -29,7 +31,11 @@ this.containerInfo = containerInfo; } - public static KotlinPackageInfo create(KmPackage kmPackage, DexClass clazz, AppView<?> appView) { + public static KotlinPackageInfo create( + KmPackage kmPackage, + DexClass clazz, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { Map<String, DexEncodedField> fieldMap = new HashMap<>(); for (DexEncodedField field : clazz.fields()) { fieldMap.put(toJvmFieldSignature(field.field).asString(), field); @@ -40,7 +46,8 @@ } return new KotlinPackageInfo( JvmExtensionsKt.getModuleName(kmPackage), - KotlinDeclarationContainerInfo.create(kmPackage, methodMap, fieldMap, appView)); + KotlinDeclarationContainerInfo.create( + kmPackage, methodMap, fieldMap, definitionSupplier, reporter)); } public void rewrite(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java index a94b6fc..802428a 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
@@ -5,10 +5,12 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import java.util.List; import kotlinx.metadata.KmProperty; import kotlinx.metadata.KmPropertyVisitor; @@ -19,35 +21,35 @@ public class KotlinPropertyInfo implements KotlinFieldLevelInfo, KotlinMethodLevelInfo { // Original flags. - final int flags; + private final int flags; // Original getter flags. E.g., for property getter. - final int getterFlags; + private final int getterFlags; // Original setter flags. E.g., for property setter. - final int setterFlags; + private final int setterFlags; // Original property name for (extension) property. Otherwise, null. - final String name; + private final String name; // Original return type information. This should never be NULL (even for setters without field). - final KotlinTypeInfo returnType; + private final KotlinTypeInfo returnType; - final KotlinTypeInfo receiverParameterType; + private final KotlinTypeInfo receiverParameterType; - final KotlinValueParameterInfo setterParameter; + private final KotlinValueParameterInfo setterParameter; - final List<KotlinTypeParameterInfo> typeParameters; + private final List<KotlinTypeParameterInfo> typeParameters; - final int jvmFlags; + private final int jvmFlags; - final KotlinJvmFieldSignatureInfo fieldSignature; + private final KotlinJvmFieldSignatureInfo fieldSignature; - final KotlinJvmMethodSignatureInfo getterSignature; + private final KotlinJvmMethodSignatureInfo getterSignature; - final KotlinJvmMethodSignatureInfo setterSignature; + private final KotlinJvmMethodSignatureInfo setterSignature; - final KotlinJvmMethodSignatureInfo syntheticMethodForAnnotations; + private final KotlinJvmMethodSignatureInfo syntheticMethodForAnnotations; private KotlinPropertyInfo( int flags, @@ -78,24 +80,28 @@ this.syntheticMethodForAnnotations = syntheticMethodForAnnotations; } - public static KotlinPropertyInfo create(KmProperty kmProperty, AppView<?> appView) { + public static KotlinPropertyInfo create( + KmProperty kmProperty, DexDefinitionSupplier definitionSupplier, Reporter reporter) { return new KotlinPropertyInfo( kmProperty.getFlags(), kmProperty.getGetterFlags(), kmProperty.getSetterFlags(), kmProperty.getName(), - KotlinTypeInfo.create(kmProperty.getReturnType(), appView), - KotlinTypeInfo.create(kmProperty.getReceiverParameterType(), appView), - KotlinValueParameterInfo.create(kmProperty.getSetterParameter(), appView), - KotlinTypeParameterInfo.create(kmProperty.getTypeParameters(), appView), + KotlinTypeInfo.create(kmProperty.getReturnType(), definitionSupplier, reporter), + KotlinTypeInfo.create(kmProperty.getReceiverParameterType(), definitionSupplier, reporter), + KotlinValueParameterInfo.create( + kmProperty.getSetterParameter(), definitionSupplier, reporter), + KotlinTypeParameterInfo.create( + kmProperty.getTypeParameters(), definitionSupplier, reporter), JvmExtensionsKt.getJvmFlags(kmProperty), - KotlinJvmFieldSignatureInfo.create(JvmExtensionsKt.getFieldSignature(kmProperty), appView), + KotlinJvmFieldSignatureInfo.create( + JvmExtensionsKt.getFieldSignature(kmProperty), definitionSupplier), KotlinJvmMethodSignatureInfo.create( - JvmExtensionsKt.getGetterSignature(kmProperty), appView), + JvmExtensionsKt.getGetterSignature(kmProperty), definitionSupplier), KotlinJvmMethodSignatureInfo.create( - JvmExtensionsKt.getSetterSignature(kmProperty), appView), + JvmExtensionsKt.getSetterSignature(kmProperty), definitionSupplier), KotlinJvmMethodSignatureInfo.create( - JvmExtensionsKt.getSyntheticMethodForAnnotations(kmProperty), appView)); + JvmExtensionsKt.getSyntheticMethodForAnnotations(kmProperty), definitionSupplier)); } @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java index 8dfe761..cc11647 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
@@ -6,8 +6,10 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import kotlinx.metadata.InconsistentKotlinMetadataException; import kotlinx.metadata.KmLambda; import kotlinx.metadata.jvm.KotlinClassHeader; @@ -34,7 +36,11 @@ } static KotlinSyntheticClassInfo create( - SyntheticClass syntheticClass, DexClass clazz, Kotlin kotlin, AppView<?> appView) { + SyntheticClass syntheticClass, + DexClass clazz, + Kotlin kotlin, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { KmLambda lambda = null; if (syntheticClass.isLambda()) { try { @@ -45,7 +51,9 @@ } } return new KotlinSyntheticClassInfo( - lambda != null ? KotlinLambdaInfo.create(clazz, lambda, appView) : null, + lambda != null + ? KotlinLambdaInfo.create(clazz, lambda, definitionSupplier, reporter) + : null, getFlavour(syntheticClass, clazz, kotlin)); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java index 974469c..b4b5354 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
@@ -5,8 +5,10 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import java.util.List; import kotlinx.metadata.KmTypeAlias; import kotlinx.metadata.KmTypeAliasVisitor; @@ -38,14 +40,15 @@ this.annotations = annotations; } - public static KotlinTypeAliasInfo create(KmTypeAlias alias, AppView<?> appView) { + public static KotlinTypeAliasInfo create( + KmTypeAlias alias, DexDefinitionSupplier definitionSupplier, Reporter reporter) { return new KotlinTypeAliasInfo( alias.getFlags(), alias.getName(), - KotlinTypeInfo.create(alias.underlyingType, appView), - KotlinTypeInfo.create(alias.expandedType, appView), - KotlinTypeParameterInfo.create(alias.getTypeParameters(), appView), - KotlinAnnotationInfo.create(alias.getAnnotations(), appView)); + KotlinTypeInfo.create(alias.underlyingType, definitionSupplier, reporter), + KotlinTypeInfo.create(alias.expandedType, definitionSupplier, reporter), + KotlinTypeParameterInfo.create(alias.getTypeParameters(), definitionSupplier, reporter), + KotlinAnnotationInfo.create(alias.getAnnotations(), definitionSupplier)); } void rewrite(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java index f00a544..204bcbb 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -5,8 +5,10 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import com.google.common.collect.ImmutableList; import java.util.List; import kotlinx.metadata.KmType; @@ -47,27 +49,30 @@ return arguments; } - static KotlinTypeInfo create(KmType kmType, AppView<?> appView) { + static KotlinTypeInfo create( + KmType kmType, DexDefinitionSupplier definitionSupplier, Reporter reporter) { if (kmType == null) { return null; } return new KotlinTypeInfo( kmType.getFlags(), - KotlinClassifierInfo.create(kmType.classifier, appView), - KotlinTypeInfo.create(kmType.getAbbreviatedType(), appView), - KotlinTypeInfo.create(kmType.getOuterType(), appView), - getArguments(kmType.getArguments(), appView), - KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmType), appView)); + KotlinClassifierInfo.create(kmType.classifier, definitionSupplier, reporter), + KotlinTypeInfo.create(kmType.getAbbreviatedType(), definitionSupplier, reporter), + KotlinTypeInfo.create(kmType.getOuterType(), definitionSupplier, reporter), + getArguments(kmType.getArguments(), definitionSupplier, reporter), + KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmType), definitionSupplier)); } private static List<KotlinTypeProjectionInfo> getArguments( - List<KmTypeProjection> projections, AppView<?> appView) { + List<KmTypeProjection> projections, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { if (projections.isEmpty()) { return EMPTY_ARGUMENTS; } ImmutableList.Builder<KotlinTypeProjectionInfo> arguments = ImmutableList.builder(); for (KmTypeProjection projection : projections) { - arguments.add(KotlinTypeProjectionInfo.create(projection, appView)); + arguments.add(KotlinTypeProjectionInfo.create(projection, definitionSupplier, reporter)); } return arguments.build(); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java index e79ea83..fd11c11 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
@@ -5,8 +5,10 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import com.google.common.collect.ImmutableList; import java.util.List; import kotlinx.metadata.KmType; @@ -45,35 +47,41 @@ } private static KotlinTypeParameterInfo create( - KmTypeParameter kmTypeParameter, AppView<?> appView) { + KmTypeParameter kmTypeParameter, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { return new KotlinTypeParameterInfo( kmTypeParameter.getFlags(), kmTypeParameter.getId(), kmTypeParameter.getName(), kmTypeParameter.getVariance(), - getUpperBounds(kmTypeParameter.getUpperBounds(), appView), - KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmTypeParameter), appView)); + getUpperBounds(kmTypeParameter.getUpperBounds(), definitionSupplier, reporter), + KotlinAnnotationInfo.create( + JvmExtensionsKt.getAnnotations(kmTypeParameter), definitionSupplier)); } static List<KotlinTypeParameterInfo> create( - List<KmTypeParameter> kmTypeParameters, AppView<?> appView) { + List<KmTypeParameter> kmTypeParameters, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { if (kmTypeParameters.isEmpty()) { return EMPTY_TYPE_PARAMETERS; } ImmutableList.Builder<KotlinTypeParameterInfo> builder = ImmutableList.builder(); for (KmTypeParameter kmTypeParameter : kmTypeParameters) { - builder.add(create(kmTypeParameter, appView)); + builder.add(create(kmTypeParameter, definitionSupplier, reporter)); } return builder.build(); } - private static List<KotlinTypeInfo> getUpperBounds(List<KmType> upperBounds, AppView<?> appView) { + private static List<KotlinTypeInfo> getUpperBounds( + List<KmType> upperBounds, DexDefinitionSupplier definitionSupplier, Reporter reporter) { if (upperBounds.isEmpty()) { return EMPTY_UPPER_BOUNDS; } ImmutableList.Builder<KotlinTypeInfo> builder = ImmutableList.builder(); for (KmType upperBound : upperBounds) { - builder.add(KotlinTypeInfo.create(upperBound, appView)); + builder.add(KotlinTypeInfo.create(upperBound, definitionSupplier, reporter)); } return builder.build(); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java index 9ab8adc..68da5db 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
@@ -5,8 +5,10 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import kotlinx.metadata.KmTypeProjection; import kotlinx.metadata.KmVariance; @@ -21,9 +23,13 @@ this.typeInfo = typeInfo; } - static KotlinTypeProjectionInfo create(KmTypeProjection kmTypeProjection, AppView<?> appView) { + static KotlinTypeProjectionInfo create( + KmTypeProjection kmTypeProjection, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { return new KotlinTypeProjectionInfo( - kmTypeProjection.getVariance(), KotlinTypeInfo.create(kmTypeProjection.getType(), appView)); + kmTypeProjection.getVariance(), + KotlinTypeInfo.create(kmTypeProjection.getType(), definitionSupplier, reporter)); } private boolean isStarProjection() {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java index d092495..ee2f99b 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
@@ -5,8 +5,10 @@ package com.android.tools.r8.kotlin; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Reporter; import com.google.common.collect.ImmutableList; import java.util.List; import kotlinx.metadata.KmType; @@ -33,7 +35,10 @@ this.varargElementType = varargElementType; } - static KotlinValueParameterInfo create(KmValueParameter kmValueParameter, AppView<?> appView) { + static KotlinValueParameterInfo create( + KmValueParameter kmValueParameter, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { if (kmValueParameter == null) { return null; } @@ -41,18 +46,21 @@ return new KotlinValueParameterInfo( kmValueParameter.getFlags(), kmValueParameter.getName(), - KotlinTypeInfo.create(kmType, appView), - KotlinTypeInfo.create(kmValueParameter.getVarargElementType(), appView)); + KotlinTypeInfo.create(kmType, definitionSupplier, reporter), + KotlinTypeInfo.create( + kmValueParameter.getVarargElementType(), definitionSupplier, reporter)); } static List<KotlinValueParameterInfo> create( - List<KmValueParameter> parameters, AppView<?> appView) { + List<KmValueParameter> parameters, + DexDefinitionSupplier definitionSupplier, + Reporter reporter) { if (parameters.isEmpty()) { return EMPTY_VALUE_PARAMETERS; } ImmutableList.Builder<KotlinValueParameterInfo> builder = ImmutableList.builder(); for (KmValueParameter parameter : parameters) { - builder.add(create(parameter, appView)); + builder.add(create(parameter, definitionSupplier, reporter)); } return builder.build(); }
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java index c57a91a..8cffa05 100644 --- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -271,7 +271,7 @@ if (holder == null || holder.isNotProgramClass()) { return; } - definition = appView.appInfo().resolveField(field); + definition = appView.appInfo().resolveField(field).getResolvedField(); if (definition == null) { // The program is already broken in the sense that it has an unresolvable field reference. // Leave it as-is.
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java index 6652d4a..f8d80cb 100644 --- a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java +++ b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.naming; - +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; @@ -22,17 +22,20 @@ private final MemberNamingStrategy strategy; private final BiPredicate<DexString, DexField> isAvailable; - public FieldNamingState(AppView<?> appView, MemberNamingStrategy strategy) { + public FieldNamingState( + AppView<? extends AppInfoWithClassHierarchy> appView, MemberNamingStrategy strategy) { this(appView, strategy, new ReservedFieldNamingState(appView)); } public FieldNamingState( - AppView<?> appView, MemberNamingStrategy strategy, ReservedFieldNamingState reservedNames) { + AppView<? extends AppInfoWithClassHierarchy> appView, + MemberNamingStrategy strategy, + ReservedFieldNamingState reservedNames) { this(appView, strategy, reservedNames, new IdentityHashMap<>()); } private FieldNamingState( - AppView<?> appView, + AppView<? extends AppInfoWithClassHierarchy> appView, MemberNamingStrategy strategy, ReservedFieldNamingState reservedNames, Map<DexType, InternalState> internalStates) { @@ -50,7 +53,7 @@ } public DexString getOrCreateNameFor(DexField field) { - DexEncodedField encodedField = appView.appInfo().resolveField(field); + DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); if (encodedField != null) { DexClass clazz = appView.definitionFor(encodedField.holder()); if (clazz == null) {
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNamingStateBase.java b/src/main/java/com/android/tools/r8/naming/FieldNamingStateBase.java index 8fbcfcd..693f373 100644 --- a/src/main/java/com/android/tools/r8/naming/FieldNamingStateBase.java +++ b/src/main/java/com/android/tools/r8/naming/FieldNamingStateBase.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.naming; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexType; @@ -12,10 +13,11 @@ abstract class FieldNamingStateBase<T> { - final AppView<?> appView; + final AppView<? extends AppInfoWithClassHierarchy> appView; final Map<DexType, T> internalStates; - FieldNamingStateBase(AppView<?> appView, Map<DexType, T> internalStates) { + FieldNamingStateBase( + AppView<? extends AppInfoWithClassHierarchy> appView, Map<DexType, T> internalStates) { this.appView = appView; this.internalStates = internalStates; }
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java index f789fe4..d133c3f 100644 --- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java +++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.naming; - +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.DexEncodedMethod; @@ -32,12 +32,12 @@ class MinifiedRenaming extends NamingLens { - final AppView<?> appView; + final AppView<? extends AppInfoWithClassHierarchy> appView; private final Map<String, String> packageRenaming; private final Map<DexItem, DexString> renaming = new IdentityHashMap<>(); MinifiedRenaming( - AppView<?> appView, + AppView<? extends AppInfoWithClassHierarchy> appView, ClassRenaming classRenaming, MethodRenaming methodRenaming, FieldRenaming fieldRenaming) { @@ -99,7 +99,7 @@ return renamed; } // If the method does not have a direct renaming, return the resolutions mapping. - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appView.appInfo().unsafeResolveMethodDueToDexFormat(method); if (resolutionResult.isSingleResolution()) { return renaming.getOrDefault(resolutionResult.getSingleTarget().method, method.name); } @@ -166,7 +166,7 @@ return true; } - ResolutionResult resolution = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolution = appView.appInfo().unsafeResolveMethodDueToDexFormat(method); assert resolution != null; if (resolution.isSingleResolution()) {
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java index 5e23d98..ab735ca 100644 --- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.naming; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexDefinition; @@ -583,7 +584,7 @@ private final Map<DexString, DexType> classRenamingsMappingToDifferentName; ProguardMapMinifiedRenaming( - AppView<?> appView, + AppView<? extends AppInfoWithClassHierarchy> appView, ClassRenaming classRenaming, MethodRenaming methodRenaming, FieldRenaming fieldRenaming,
diff --git a/src/main/java/com/android/tools/r8/naming/ReservedFieldNamingState.java b/src/main/java/com/android/tools/r8/naming/ReservedFieldNamingState.java index 9a0051b..4e3e98c 100644 --- a/src/main/java/com/android/tools/r8/naming/ReservedFieldNamingState.java +++ b/src/main/java/com/android/tools/r8/naming/ReservedFieldNamingState.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.naming; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; @@ -13,7 +14,7 @@ class ReservedFieldNamingState extends FieldNamingStateBase<InternalState> { - ReservedFieldNamingState(AppView<?> appView) { + ReservedFieldNamingState(AppView<? extends AppInfoWithClassHierarchy> appView) { super(appView, new IdentityHashMap<>()); }
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java index 8e5c3c3..1cdeec3 100644 --- a/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java +++ b/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java
@@ -157,7 +157,7 @@ DexEncodedMethod definition = subclass.lookupVirtualMethod(method); if (definition == null) { DexEncodedMethod resolutionTarget = - appView.appInfo().resolveMethodOnClass(subclass, method).getSingleTarget(); + appView.appInfo().resolveMethodOnClass(method, subclass).getSingleTarget(); if (resolutionTarget == null || resolutionTarget.isAbstract()) { // The fact that this class does not declare the bridge (or the bridge is abstract) should // not prevent us from hoisting the bridge.
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java index 8315925..5da8e5f 100644 --- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java +++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -6,11 +6,13 @@ import static com.android.tools.r8.dex.Constants.ACC_PRIVATE; import static com.android.tools.r8.dex.Constants.ACC_PROTECTED; import static com.android.tools.r8.dex.Constants.ACC_PUBLIC; +import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLense; import com.android.tools.r8.graph.InnerClassAttribute; @@ -82,43 +84,69 @@ } private void publicizeType(DexType type) { - DexClass clazz = application.definitionFor(type); - if (clazz != null && clazz.isProgramClass()) { - clazz.accessFlags.promoteToPublic(); - - // Publicize fields. - clazz.forEachField(field -> field.accessFlags.promoteToPublic()); - - // Publicize methods. - Set<DexEncodedMethod> privateInstanceEncodedMethods = new LinkedHashSet<>(); - clazz.forEachMethod(encodedMethod -> { - if (publicizeMethod(clazz, encodedMethod)) { - privateInstanceEncodedMethods.add(encodedMethod); - } - }); - if (!privateInstanceEncodedMethods.isEmpty()) { - clazz.virtualizeMethods(privateInstanceEncodedMethods); - } - - // Publicize inner class attribute. - InnerClassAttribute attr = clazz.getInnerClassAttributeForThisClass(); - if (attr != null) { - int accessFlags = ((attr.getAccess() | ACC_PUBLIC) & ~ACC_PRIVATE) & ~ACC_PROTECTED; - clazz.replaceInnerClassAttributeForThisClass( - new InnerClassAttribute( - accessFlags, attr.getInner(), attr.getOuter(), attr.getInnerName())); - } + DexProgramClass clazz = asProgramClassOrNull(application.definitionFor(type)); + if (clazz != null) { + publicizeClass(clazz); } - subtypingInfo.forAllImmediateExtendsSubtypes(type, this::publicizeType); } - private boolean publicizeMethod(DexClass holder, DexEncodedMethod encodedMethod) { - MethodAccessFlags accessFlags = encodedMethod.accessFlags; + private void publicizeClass(DexProgramClass clazz) { + clazz.accessFlags.promoteToPublic(); + + // Publicize fields. + clazz.forEachField( + field -> { + if (field.isPublic()) { + return; + } + if (appView.appInfo().isPinned(field.field)) { + // TODO(b/131130038): Also do not publicize package-private and protected fields that + // are kept. + if (field.isPrivate()) { + return; + } + } + field.accessFlags.promoteToPublic(); + }); + + // Publicize methods. + Set<DexEncodedMethod> privateInstanceMethods = new LinkedHashSet<>(); + clazz.forEachMethod( + method -> { + if (publicizeMethod(clazz, method)) { + privateInstanceMethods.add(method); + } + }); + if (!privateInstanceMethods.isEmpty()) { + clazz.virtualizeMethods(privateInstanceMethods); + } + + // Publicize inner class attribute. + InnerClassAttribute attr = clazz.getInnerClassAttributeForThisClass(); + if (attr != null) { + int accessFlags = ((attr.getAccess() | ACC_PUBLIC) & ~ACC_PRIVATE) & ~ACC_PROTECTED; + clazz.replaceInnerClassAttributeForThisClass( + new InnerClassAttribute( + accessFlags, attr.getInner(), attr.getOuter(), attr.getInnerName())); + } + } + + private boolean publicizeMethod(DexProgramClass holder, DexEncodedMethod method) { + MethodAccessFlags accessFlags = method.accessFlags; if (accessFlags.isPublic()) { return false; } - if (!accessFlags.isPrivate() || appView.dexItemFactory().isConstructor(encodedMethod.method)) { + // If this method is mentioned in keep rules, do not transform (rule applications changed). + if (appView.appInfo().isPinned(method.method)) { + // TODO(b/131130038): Also do not publicize package-private and protected methods that are + // kept. + if (method.isPrivate()) { + return false; + } + } + + if (!accessFlags.isPrivate() || appView.dexItemFactory().isConstructor(method.method)) { // TODO(b/150589374): This should check for dispatch targets or just abandon in // package-private. accessFlags.promoteToPublic(); @@ -126,10 +154,6 @@ } if (!accessFlags.isStatic()) { - // If this method is mentioned in keep rules, do not transform (rule applications changed). - if (appView.appInfo().isPinned(encodedMethod.method)) { - return false; - } // We can't publicize private instance methods in interfaces or methods that are copied from // interfaces to lambda-desugared classes because this will be added as a new default method. @@ -138,20 +162,20 @@ return false; } - boolean wasSeen = methodPoolCollection.markIfNotSeen(holder, encodedMethod.method); + boolean wasSeen = methodPoolCollection.markIfNotSeen(holder, method.method); if (wasSeen) { // We can't do anything further because even renaming is not allowed due to the keep rule. - if (appView.rootSet().mayNotBeMinified(encodedMethod.method, appView)) { + if (appView.rootSet().mayNotBeMinified(method.method, appView)) { return false; } // TODO(b/111118390): Renaming will enable more private instance methods to be publicized. return false; } - lenseBuilder.add(encodedMethod.method); + lenseBuilder.add(method.method); accessFlags.promoteToFinal(); accessFlags.promoteToPublic(); // The method just became public and is therefore not a library override. - encodedMethod.setLibraryMethodOverride(OptionalBool.FALSE); + method.setLibraryMethodOverride(OptionalBool.FALSE); return true; }
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java index 42e03e0..a3e4666 100644 --- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java +++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -15,12 +15,13 @@ import com.android.tools.r8.graph.FieldAccessInfo; import com.android.tools.r8.graph.FieldAccessInfoCollection; import com.android.tools.r8.graph.GraphLense; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.InternalOptions; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import java.util.Map; -import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; @@ -114,7 +115,7 @@ } private DexEncodedMethod classLookup(DexMethod method) { - return appView.appInfo().resolveMethodOnClass(method.holder, method).getSingleTarget(); + return appView.appInfo().resolveMethodOnClass(method, method.holder).getSingleTarget(); } private DexEncodedMethod interfaceLookup(DexMethod method) { @@ -122,11 +123,11 @@ } private DexEncodedMethod anyLookup(DexMethod method) { - return appView.appInfo().resolveMethod(method.holder, method).getSingleTarget(); + return appView.appInfo().unsafeResolveMethodDueToDexFormat(method).getSingleTarget(); } private void computeMethodRebinding( - Map<DexMethod, Set<DexEncodedMethod>> methodsWithContexts, + Map<DexMethod, ProgramMethodSet> methodsWithContexts, Function<DexMethod, DexEncodedMethod> lookupTarget, Type invokeType) { for (DexMethod method : methodsWithContexts.keySet()) { @@ -158,9 +159,9 @@ // If the target class is not public but the targeted method is, we might run into // visibility problems when rebinding. final DexEncodedMethod finalTarget = target; - Set<DexEncodedMethod> contexts = methodsWithContexts.get(method); + ProgramMethodSet contexts = methodsWithContexts.get(method); if (contexts.stream() - .anyMatch(context -> mayNeedBridgeForVisibility(context.holder(), finalTarget))) { + .anyMatch(context -> mayNeedBridgeForVisibility(context, finalTarget))) { target = insertBridgeForVisibilityIfNeeded( method, target, originalClass, targetClass, lookupTarget); @@ -216,16 +217,18 @@ return findHolderForInterfaceMethodBridge(superClass.asProgramClass(), iface); } - private boolean mayNeedBridgeForVisibility(DexType context, DexEncodedMethod method) { + private boolean mayNeedBridgeForVisibility(ProgramMethod context, DexEncodedMethod method) { DexType holderType = method.holder(); DexClass holder = appView.definitionFor(holderType); if (holder == null) { return false; } ConstraintWithTarget classVisibility = - ConstraintWithTarget.deriveConstraint(context, holderType, holder.accessFlags, appView); + ConstraintWithTarget.deriveConstraint( + context.getHolder(), holderType, holder.accessFlags, appView); ConstraintWithTarget methodVisibility = - ConstraintWithTarget.deriveConstraint(context, holderType, method.accessFlags, appView); + ConstraintWithTarget.deriveConstraint( + context.getHolder(), holderType, method.accessFlags, appView); // We may need bridge for visibility if the target class is not visible while the target method // is visible from the calling context. return classVisibility == ConstraintWithTarget.NEVER @@ -297,8 +300,8 @@ } private void computeFieldRebindingForIndirectAccessWithContexts( - DexField field, Set<DexEncodedMethod> contexts) { - DexEncodedField target = appView.appInfo().resolveField(field); + DexField field, ProgramMethodSet contexts) { + DexEncodedField target = appView.appInfo().resolveField(field).getResolvedField(); if (target == null) { assert false; return; @@ -315,14 +318,14 @@ .allMatch( context -> isMemberVisibleFromOriginalContext( - appView, context.holder(), target.holder(), target.accessFlags))) { + appView, context, target.holder(), target.accessFlags))) { builder.map( field, lense.lookupField(validTargetFor(target.field, field, DexClass::lookupField))); } } public static boolean isTypeVisibleFromContext( - AppView<?> appView, DexType context, DexType type) { + AppView<?> appView, ProgramMethod context, DexType type) { DexType baseType = type.toBaseType(appView.dexItemFactory()); if (baseType.isPrimitiveType()) { return true; @@ -331,26 +334,28 @@ } public static boolean isClassTypeVisibleFromContext( - AppView<?> appView, DexType context, DexType type) { + AppView<?> appView, ProgramMethod context, DexType type) { assert type.isClassType(); DexClass clazz = appView.definitionFor(type); return clazz != null && isClassTypeVisibleFromContext(appView, context, clazz); } public static boolean isClassTypeVisibleFromContext( - AppView<?> appView, DexType context, DexClass clazz) { + AppView<?> appView, ProgramMethod context, DexClass clazz) { ConstraintWithTarget classVisibility = - ConstraintWithTarget.deriveConstraint(context, clazz.type, clazz.accessFlags, appView); + ConstraintWithTarget.deriveConstraint( + context.getHolder(), clazz.type, clazz.accessFlags, appView); return classVisibility != ConstraintWithTarget.NEVER; } public static boolean isMemberVisibleFromOriginalContext( - AppView<?> appView, DexType context, DexType holder, AccessFlags<?> memberAccessFlags) { + AppView<?> appView, ProgramMethod context, DexType holder, AccessFlags<?> memberAccessFlags) { if (!isClassTypeVisibleFromContext(appView, context, holder)) { return false; } ConstraintWithTarget memberVisibility = - ConstraintWithTarget.deriveConstraint(context, holder, memberAccessFlags, appView); + ConstraintWithTarget.deriveConstraint( + context.getHolder(), holder, memberAccessFlags, appView); return memberVisibility != ConstraintWithTarget.NEVER; }
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java index 45892a2..96dd07b 100644 --- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java +++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -83,7 +83,7 @@ if (kind == InvokeKind.SUPER) { // This is a visibility forward, so check for the direct target. DexEncodedMethod targetMethod = - appView.appInfo().resolveMethod(target.holder, target).getSingleTarget(); + appView.appInfo().unsafeResolveMethodDueToDexFormat(target).getSingleTarget(); if (targetMethod != null && targetMethod.accessFlags.isPublic()) { if (Log.ENABLED) { Log.info(
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java index a4caad6..aaf83b1 100644 --- a/src/main/java/com/android/tools/r8/relocator/Relocator.java +++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -12,7 +12,6 @@ import com.android.tools.r8.dex.Marker; import com.android.tools.r8.dex.Marker.Tool; import com.android.tools.r8.graph.AppInfo; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppServices; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; @@ -81,7 +80,7 @@ try { DexApplication app = new ApplicationReader(inputApp, options, timing).read(executor); - AppInfo appInfo = new AppInfoWithClassHierarchy(app); + AppInfo appInfo = new AppInfo(app); AppView<?> appView = AppView.createForRelocator(appInfo, options); appView.setAppServices(AppServices.builder(appView).build());
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java index 77edcc6..308cf69 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -50,6 +50,7 @@ import com.android.tools.r8.utils.PredicateSet; import com.android.tools.r8.utils.TraversalContinuation; import com.android.tools.r8.utils.Visibility; +import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedSet.Builder; @@ -121,15 +122,15 @@ /** Information about instantiated classes and their allocation sites. */ private final ObjectAllocationInfoCollectionImpl objectAllocationInfoCollection; /** Set of all methods referenced in virtual invokes, along with calling context. */ - public final SortedMap<DexMethod, Set<DexEncodedMethod>> virtualInvokes; + public final SortedMap<DexMethod, ProgramMethodSet> virtualInvokes; /** Set of all methods referenced in interface invokes, along with calling context. */ - public final SortedMap<DexMethod, Set<DexEncodedMethod>> interfaceInvokes; + public final SortedMap<DexMethod, ProgramMethodSet> interfaceInvokes; /** Set of all methods referenced in super invokes, along with calling context. */ - public final SortedMap<DexMethod, Set<DexEncodedMethod>> superInvokes; + public final SortedMap<DexMethod, ProgramMethodSet> superInvokes; /** Set of all methods referenced in direct invokes, along with calling context. */ - public final SortedMap<DexMethod, Set<DexEncodedMethod>> directInvokes; + public final SortedMap<DexMethod, ProgramMethodSet> directInvokes; /** Set of all methods referenced in static invokes, along with calling context. */ - public final SortedMap<DexMethod, Set<DexEncodedMethod>> staticInvokes; + public final SortedMap<DexMethod, ProgramMethodSet> staticInvokes; /** * Set of live call sites in the code. Note that if desugaring has taken place call site objects * will have been removed from the code. @@ -208,11 +209,11 @@ SortedSet<DexMethod> liveMethods, FieldAccessInfoCollectionImpl fieldAccessInfoCollection, ObjectAllocationInfoCollectionImpl objectAllocationInfoCollection, - SortedMap<DexMethod, Set<DexEncodedMethod>> virtualInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> interfaceInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> superInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> directInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> staticInvokes, + SortedMap<DexMethod, ProgramMethodSet> virtualInvokes, + SortedMap<DexMethod, ProgramMethodSet> interfaceInvokes, + SortedMap<DexMethod, ProgramMethodSet> superInvokes, + SortedMap<DexMethod, ProgramMethodSet> directInvokes, + SortedMap<DexMethod, ProgramMethodSet> staticInvokes, Set<DexCallSite> callSites, Set<DexReference> pinnedItems, Map<DexReference, ProguardMemberRule> mayHaveSideEffects, @@ -280,7 +281,7 @@ } public AppInfoWithLiveness( - AppInfoWithClassHierarchy appInfoWithSubtyping, + AppInfoWithClassHierarchy appInfoWithClassHierarchy, Set<DexType> deadProtoTypes, Set<DexType> missingTypes, Set<DexType> liveTypes, @@ -293,11 +294,11 @@ SortedSet<DexMethod> liveMethods, FieldAccessInfoCollectionImpl fieldAccessInfoCollection, ObjectAllocationInfoCollectionImpl objectAllocationInfoCollection, - SortedMap<DexMethod, Set<DexEncodedMethod>> virtualInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> interfaceInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> superInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> directInvokes, - SortedMap<DexMethod, Set<DexEncodedMethod>> staticInvokes, + SortedMap<DexMethod, ProgramMethodSet> virtualInvokes, + SortedMap<DexMethod, ProgramMethodSet> interfaceInvokes, + SortedMap<DexMethod, ProgramMethodSet> superInvokes, + SortedMap<DexMethod, ProgramMethodSet> directInvokes, + SortedMap<DexMethod, ProgramMethodSet> staticInvokes, Set<DexCallSite> callSites, Set<DexReference> pinnedItems, Map<DexReference, ProguardMemberRule> mayHaveSideEffects, @@ -321,7 +322,7 @@ EnumValueInfoMapCollection enumValueInfoMaps, Set<DexType> constClassReferences, Map<DexType, Visibility> initClassReferences) { - super(appInfoWithSubtyping); + super(appInfoWithClassHierarchy); this.deadProtoTypes = deadProtoTypes; this.missingTypes = missingTypes; this.liveTypes = liveTypes; @@ -853,7 +854,8 @@ } DexType holder = field.holder(); return fieldAccessInfo.isWrittenOnlyInMethodSatisfying( - method -> method.isInstanceInitializer() && method.holder() == holder); + method -> + method.getDefinition().isInstanceInitializer() && method.getHolderType() == holder); } public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializer(DexEncodedField field) { @@ -885,15 +887,15 @@ return builder.build(); } - private static <T extends PresortedComparable<T>, S> - SortedMap<T, Set<S>> rewriteKeysConservativelyWhileMergingValues( - Map<T, Set<S>> original, Function<T, Set<T>> rewrite) { - SortedMap<T, Set<S>> result = new TreeMap<>(PresortedComparable::slowCompare); + private static <T extends PresortedComparable<T>> + SortedMap<T, ProgramMethodSet> rewriteKeysConservativelyWhileMergingValues( + Map<T, ProgramMethodSet> original, Function<T, Set<T>> rewrite) { + SortedMap<T, ProgramMethodSet> result = new TreeMap<>(PresortedComparable::slowCompare); for (T item : original.keySet()) { Set<T> rewrittenKeys = rewrite.apply(item); for (T rewrittenKey : rewrittenKeys) { result - .computeIfAbsent(rewrittenKey, k -> Sets.newIdentityHashSet()) + .computeIfAbsent(rewrittenKey, k -> ProgramMethodSet.create()) .addAll(original.get(item)); } } @@ -1053,7 +1055,7 @@ public DexEncodedMethod lookupSingleTarget( Type type, DexMethod target, - DexType invocationContext, + ProgramMethod context, LibraryModeledPredicate modeledPredicate) { assert checkIfObsolete(); DexType holder = target.holder; @@ -1062,15 +1064,15 @@ } switch (type) { case VIRTUAL: - return lookupSingleVirtualTarget(target, invocationContext, false, modeledPredicate); + return lookupSingleVirtualTarget(target, context, false, modeledPredicate); case INTERFACE: - return lookupSingleVirtualTarget(target, invocationContext, true, modeledPredicate); + return lookupSingleVirtualTarget(target, context, true, modeledPredicate); case DIRECT: - return lookupDirectTarget(target, invocationContext); + return lookupDirectTarget(target, context); case STATIC: - return lookupStaticTarget(target, invocationContext); + return lookupStaticTarget(target, context); case SUPER: - return lookupSuperTarget(target, invocationContext); + return lookupSuperTarget(target, context); default: return null; } @@ -1079,44 +1081,39 @@ public ProgramMethod lookupSingleProgramTarget( Type type, DexMethod target, - DexType invocationContext, + ProgramMethod context, LibraryModeledPredicate modeledPredicate) { - return asProgramMethodOrNull( - lookupSingleTarget(type, target, invocationContext, modeledPredicate), this); + return asProgramMethodOrNull(lookupSingleTarget(type, target, context, modeledPredicate), this); } /** For mapping invoke virtual instruction to single target method. */ public DexEncodedMethod lookupSingleVirtualTarget( - DexMethod method, DexType invocationContext, boolean isInterface) { + DexMethod method, ProgramMethod context, boolean isInterface) { assert checkIfObsolete(); return lookupSingleVirtualTarget( - method, invocationContext, isInterface, type -> false, method.holder, null); + method, context, isInterface, type -> false, method.holder, null); } /** For mapping invoke virtual instruction to single target method. */ public DexEncodedMethod lookupSingleVirtualTarget( DexMethod method, - DexType invocationContext, + ProgramMethod context, boolean isInterface, LibraryModeledPredicate modeledPredicate) { assert checkIfObsolete(); return lookupSingleVirtualTarget( - method, invocationContext, isInterface, modeledPredicate, method.holder, null); + method, context, isInterface, modeledPredicate, method.holder, null); } public DexEncodedMethod lookupSingleVirtualTarget( DexMethod method, - DexType invocationContext, + ProgramMethod context, boolean isInterface, LibraryModeledPredicate modeledPredicate, DexType refinedReceiverType, ClassTypeElement receiverLowerBoundType) { assert checkIfObsolete(); assert refinedReceiverType != null; - - DexProgramClass invocationClass = asProgramClassOrNull(definitionFor(invocationContext)); - assert invocationClass != null; - if (!refinedReceiverType.isClassType()) { // The refined receiver is not of class type and we will not be able to find a single target // (it is either primitive or array). @@ -1138,9 +1135,9 @@ return cachedItem; } SingleResolutionResult resolution = - resolveMethod(initialResolutionHolder, method).asSingleResolution(); + resolveMethodOn(initialResolutionHolder, method).asSingleResolution(); if (resolution == null - || resolution.isAccessibleForVirtualDispatchFrom(invocationClass, this).isFalse()) { + || resolution.isAccessibleForVirtualDispatchFrom(context.getHolder(), this).isFalse()) { return null; } // If the method is modeled, return the resolution. @@ -1189,7 +1186,7 @@ LookupResultSuccess lookupResult = resolution .lookupVirtualDispatchTargets( - invocationClass, this, refinedReceiverClass.asProgramClass(), refinedLowerBound) + context.getHolder(), this, refinedReceiverClass.asProgramClass(), refinedLowerBound) .asLookupResultSuccess(); if (lookupResult != null && !lookupResult.isIncomplete()) { LookupTarget singleTarget = lookupResult.getSingleLookupTarget(); @@ -1394,7 +1391,7 @@ return TraversalContinuation.BREAK; } else { SingleResolutionResult resolution = - resolveMethod(clazz, dexItemFactory().objectMembers.finalize) + resolveMethodOn(clazz, dexItemFactory().objectMembers.finalize) .asSingleResolution(); if (resolution != null && resolution.getResolvedHolder().isProgramClass()) { return TraversalContinuation.BREAK;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java index 9604389..f2dddae 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -34,6 +34,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexClasspathClass; import com.android.tools.r8.graph.DexDefinition; +import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMember; import com.android.tools.r8.graph.DexEncodedMethod; @@ -55,11 +56,13 @@ import com.android.tools.r8.graph.EnumValueInfoMapCollection; import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl; import com.android.tools.r8.graph.FieldAccessInfoImpl; +import com.android.tools.r8.graph.FieldResolutionResult; import com.android.tools.r8.graph.InnerClassAttribute; import com.android.tools.r8.graph.LookupLambdaTarget; import com.android.tools.r8.graph.LookupTarget; import com.android.tools.r8.graph.ObjectAllocationInfoCollectionImpl; import com.android.tools.r8.graph.PresortedComparable; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.graph.ResolutionResult.FailedResolutionResult; @@ -84,6 +87,7 @@ import com.android.tools.r8.ir.desugar.LambdaClass; import com.android.tools.r8.ir.desugar.LambdaDescriptor; import com.android.tools.r8.ir.desugar.LambdaRewriter; +import com.android.tools.r8.kotlin.KotlinMetadataEnqueuerExtension; import com.android.tools.r8.logging.Log; import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction; import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction; @@ -103,6 +107,7 @@ import com.android.tools.r8.utils.Timing; import com.android.tools.r8.utils.Visibility; import com.android.tools.r8.utils.WorkList; +import com.android.tools.r8.utils.collections.ProgramFieldSet; import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.base.Equivalence.Wrapper; import com.google.common.collect.ImmutableSet; @@ -184,12 +189,13 @@ private ProguardClassFilter dontWarnPatterns; private final EnqueuerUseRegistryFactory useRegistryFactory; private AnnotationRemover.Builder annotationRemoverBuilder; + private final DexDefinitionSupplier enqueuerDefinitionSupplier; - private final Map<DexMethod, Set<DexEncodedMethod>> virtualInvokes = new IdentityHashMap<>(); - private final Map<DexMethod, Set<DexEncodedMethod>> interfaceInvokes = new IdentityHashMap<>(); - private final Map<DexMethod, Set<DexEncodedMethod>> superInvokes = new IdentityHashMap<>(); - private final Map<DexMethod, Set<DexEncodedMethod>> directInvokes = new IdentityHashMap<>(); - private final Map<DexMethod, Set<DexEncodedMethod>> staticInvokes = new IdentityHashMap<>(); + private final Map<DexMethod, ProgramMethodSet> virtualInvokes = new IdentityHashMap<>(); + private final Map<DexMethod, ProgramMethodSet> interfaceInvokes = new IdentityHashMap<>(); + private final Map<DexMethod, ProgramMethodSet> superInvokes = new IdentityHashMap<>(); + private final Map<DexMethod, ProgramMethodSet> directInvokes = new IdentityHashMap<>(); + private final Map<DexMethod, ProgramMethodSet> staticInvokes = new IdentityHashMap<>(); private final FieldAccessInfoCollectionImpl fieldAccessInfoCollection = new FieldAccessInfoCollectionImpl(); private final ObjectAllocationInfoCollectionImpl.Builder objectAllocationInfoCollection; @@ -204,7 +210,7 @@ private final Map<DexEncodedMethod, ProgramMethodSet> superInvokeDependencies = Maps.newIdentityHashMap(); /** Set of instance fields that can be reached by read/write operations. */ - private final Map<DexProgramClass, SetWithReason<DexEncodedField>> reachableInstanceFields = + private final Map<DexProgramClass, ProgramFieldSet> reachableInstanceFields = Maps.newIdentityHashMap(); /** @@ -272,7 +278,7 @@ /** * Set of fields that belong to live classes and can be reached by invokes. These need to be kept. */ - private final SetWithReason<DexEncodedField> liveFields; + private final LiveFieldsSet liveFields; /** * Set of service types (from META-INF/services/) that may have been instantiated reflectively via @@ -361,7 +367,6 @@ && mode.isInitialOrFinalTreeShaking()) { registerAnalysis(new ProtoEnqueuerExtension(appView)); } - liveTypes = new SetWithReportedReason<>(); initializedTypes = new SetWithReportedReason<>(); targetedMethods = new SetWithReason<>(graphReporter::registerMethod); @@ -370,7 +375,7 @@ // likely contain two methods. Thus the default capacity of 2. failedResolutionTargets = SetUtils.newIdentityHashSet(2); liveMethods = new LiveMethodsSet(graphReporter::registerMethod); - liveFields = new SetWithReason<>(graphReporter::registerField); + liveFields = new LiveFieldsSet(graphReporter::registerField); lambdaRewriter = options.desugarState == DesugarState.ON ? new LambdaRewriter(appView) : null; objectAllocationInfoCollection = @@ -383,6 +388,8 @@ } else { desugaredLibraryWrapperAnalysis = null; } + + enqueuerDefinitionSupplier = new EnqueuerDefinitionSupplier(appView, this); } private AppInfoWithClassHierarchy appInfo() { @@ -484,6 +491,33 @@ recordTypeReference(field.type); } + public DexDefinition definitionFor(DexReference reference) { + if (reference.isDexType()) { + return definitionFor(reference.asDexType()); + } else if (reference.isDexMethod()) { + return definitionFor(reference.asDexMethod()); + } else { + assert reference.isDexField(); + return definitionFor(reference.asDexField()); + } + } + + public DexEncodedField definitionFor(DexField field) { + DexClass clazz = definitionFor(field.holder); + if (clazz == null) { + return null; + } + return clazz.lookupField(field); + } + + public DexEncodedMethod definitionFor(DexMethod method) { + DexClass clazz = definitionFor(method.holder); + if (clazz == null) { + return null; + } + return clazz.lookupMethod(method); + } + private DexClass definitionFor(DexType type) { DexClass clazz = appView.definitionFor(type); if (clazz == null) { @@ -610,13 +644,12 @@ } } } else if (item.isDexEncodedField()) { - DexEncodedField dexEncodedField = item.asDexEncodedField(); - DexProgramClass holder = getProgramClassOrNull(dexEncodedField.holder()); + DexEncodedField field = item.asDexEncodedField(); + DexProgramClass holder = getProgramClassOrNull(field.holder()); if (holder != null) { workList.enqueueMarkFieldKeptAction( - holder, - dexEncodedField, - graphReporter.reportKeepField(precondition, rules, dexEncodedField)); + new ProgramField(holder, field), + graphReporter.reportKeepField(precondition, rules, field)); } } else if (item.isDexEncodedMethod()) { DexEncodedMethod encodedMethod = item.asDexEncodedMethod(); @@ -672,47 +705,42 @@ // private boolean registerMethodWithTargetAndContext( - Map<DexMethod, Set<DexEncodedMethod>> seen, DexMethod method, ProgramMethod context) { + Map<DexMethod, ProgramMethodSet> seen, DexMethod method, ProgramMethod context) { DexType baseHolder = method.holder.toBaseType(appView.dexItemFactory()); if (baseHolder.isClassType()) { markTypeAsLive(baseHolder, clazz -> graphReporter.reportClassReferencedFrom(clazz, context)); - return seen.computeIfAbsent(method, ignore -> Sets.newIdentityHashSet()) - .add(context.getDefinition()); + return seen.computeIfAbsent(method, ignore -> ProgramMethodSet.create()).add(context); } return false; } public boolean registerFieldRead(DexField field, ProgramMethod context) { - return registerFieldAccess(field, context.getDefinition(), true, false); - } - - public boolean registerFieldReadFromAnnotation(DexField field) { - return registerFieldAccess(field, DexEncodedMethod.ANNOTATION_REFERENCE, true, false); + return registerFieldAccess(field, context, true, false); } public boolean registerReflectiveFieldRead(DexField field, ProgramMethod context) { - return registerFieldAccess(field, context.getDefinition(), true, true); + return registerFieldAccess(field, context, true, true); } public boolean registerFieldWrite(DexField field, ProgramMethod context) { - return registerFieldAccess(field, context.getDefinition(), false, false); + return registerFieldAccess(field, context, false, false); } public boolean registerReflectiveFieldWrite(DexField field, ProgramMethod context) { - return registerFieldAccess(field, context.getDefinition(), false, true); + return registerFieldAccess(field, context, false, true); } public boolean registerReflectiveFieldAccess(DexField field, ProgramMethod context) { - boolean changed = registerFieldAccess(field, context.getDefinition(), true, true); - changed |= registerFieldAccess(field, context.getDefinition(), false, true); + boolean changed = registerFieldAccess(field, context, true, true); + changed |= registerFieldAccess(field, context, false, true); return changed; } private boolean registerFieldAccess( - DexField field, DexEncodedMethod context, boolean isRead, boolean isReflective) { + DexField field, ProgramMethod context, boolean isRead, boolean isReflective) { FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field); if (info == null) { - DexEncodedField encodedField = resolveField(field); + DexEncodedField encodedField = resolveField(field).getResolvedField(); // If the field does not exist, then record this in the mapping, such that we don't have to // resolve the field the next time. @@ -751,8 +779,7 @@ bootstrapMethods.add(callSite.bootstrapMethod.asMethod()); } - DexProgramClass contextHolder = context.getHolder(); - LambdaDescriptor descriptor = LambdaDescriptor.tryInfer(callSite, appInfo, contextHolder); + LambdaDescriptor descriptor = LambdaDescriptor.tryInfer(callSite, appInfo, context); if (descriptor == null) { return; } @@ -762,14 +789,13 @@ assert contextMethod.getCode().isCfCode() : "Unexpected input type with lambdas"; CfCode code = contextMethod.getCode().asCfCode(); if (code != null) { - LambdaClass lambdaClass = - lambdaRewriter.getOrCreateLambdaClass(descriptor, contextMethod.holder()); + LambdaClass lambdaClass = lambdaRewriter.getOrCreateLambdaClass(descriptor, context); lambdaClasses.put(lambdaClass.type, new Pair<>(lambdaClass, context)); lambdaCallSites .computeIfAbsent(contextMethod, k -> new IdentityHashMap<>()) .put(callSite, lambdaClass); if (lambdaClass.descriptor.interfaces.contains(appView.dexItemFactory().serializableType)) { - classesWithSerializableLambdas.add(contextHolder); + classesWithSerializableLambdas.add(context.getHolder()); } } if (descriptor.delegatesToLambdaImplMethod()) { @@ -1137,43 +1163,45 @@ } private boolean traceInstanceFieldRead( - DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) { - if (!registerFieldRead(field, currentMethod)) { + DexField fieldReference, ProgramMethod currentMethod, boolean fromMethodHandle) { + if (!registerFieldRead(fieldReference, currentMethod)) { return false; } // Must mark the field as targeted even if it does not exist. - markFieldAsTargeted(field, currentMethod); + markFieldAsTargeted(fieldReference, currentMethod); - DexEncodedField encodedField = resolveField(field); - if (encodedField == null) { + FieldResolutionResult resolutionResult = resolveField(fieldReference); + if (resolutionResult.isFailedOrUnknownResolution()) { + return false; + } + + ProgramField field = + resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + if (field == null) { + // No need to trace into the non-program code. return false; } if (fromMethodHandle) { - fieldAccessInfoCollection.get(encodedField.field).setReadFromMethodHandle(); - } - - DexProgramClass clazz = getProgramClassOrNull(encodedField.holder()); - if (clazz == null) { - return false; + fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle(); } if (Log.ENABLED) { - Log.verbose(getClass(), "Register Iget `%s`.", field); + Log.verbose(getClass(), "Register Iget `%s`.", fieldReference); } // If unused interface removal is enabled, then we won't necessarily mark the actual holder of // the field as live, if the holder is an interface. if (appView.options().enableUnusedInterfaceRemoval) { - if (encodedField.field != field) { - markTypeAsLive(clazz, graphReporter.reportClassReferencedFrom(clazz, currentMethod)); - markTypeAsLive(encodedField.field.type, classReferencedFromReporter(currentMethod)); + if (field.getReference() != fieldReference) { + markTypeAsLive( + field.getHolder(), + graphReporter.reportClassReferencedFrom(field.getHolder(), currentMethod)); } } - workList.enqueueMarkReachableFieldAction( - clazz, encodedField, KeepReason.fieldReferencedIn(currentMethod)); + workList.enqueueMarkReachableFieldAction(field, KeepReason.fieldReferencedIn(currentMethod)); return true; } @@ -1186,43 +1214,46 @@ } private boolean traceInstanceFieldWrite( - DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) { - if (!registerFieldWrite(field, currentMethod)) { + DexField fieldReference, ProgramMethod currentMethod, boolean fromMethodHandle) { + if (!registerFieldWrite(fieldReference, currentMethod)) { return false; } // Must mark the field as targeted even if it does not exist. - markFieldAsTargeted(field, currentMethod); + markFieldAsTargeted(fieldReference, currentMethod); - DexEncodedField encodedField = resolveField(field); - if (encodedField == null) { + FieldResolutionResult resolutionResult = resolveField(fieldReference); + if (resolutionResult.isFailedOrUnknownResolution()) { + return false; + } + + ProgramField field = + resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + if (field == null) { + // No need to trace into the non-program code. return false; } if (fromMethodHandle) { - fieldAccessInfoCollection.get(encodedField.field).setWrittenFromMethodHandle(); - } - - DexProgramClass clazz = getProgramClassOrNull(encodedField.holder()); - if (clazz == null) { - return false; + fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle(); } if (Log.ENABLED) { - Log.verbose(getClass(), "Register Iput `%s`.", field); + Log.verbose(getClass(), "Register Iput `%s`.", fieldReference); } // If unused interface removal is enabled, then we won't necessarily mark the actual holder of // the field as live, if the holder is an interface. if (appView.options().enableUnusedInterfaceRemoval) { - if (encodedField.field != field) { - markTypeAsLive(clazz, graphReporter.reportClassReferencedFrom(clazz, currentMethod)); - markTypeAsLive(encodedField.field.type, classReferencedFromReporter(currentMethod)); + if (field.getReference() != fieldReference) { + markTypeAsLive( + field.getHolder(), + graphReporter.reportClassReferencedFrom(field.getHolder(), currentMethod)); } } KeepReason reason = KeepReason.fieldReferencedIn(currentMethod); - workList.enqueueMarkReachableFieldAction(clazz, encodedField, reason); + workList.enqueueMarkReachableFieldAction(field, reason); return true; } @@ -1235,30 +1266,31 @@ } private boolean traceStaticFieldRead( - DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) { - if (!registerFieldRead(field, currentMethod)) { + DexField fieldReference, ProgramMethod currentMethod, boolean fromMethodHandle) { + if (!registerFieldRead(fieldReference, currentMethod)) { return false; } - DexEncodedField encodedField = resolveField(field); - if (encodedField == null) { + FieldResolutionResult resolutionResult = resolveField(fieldReference); + if (resolutionResult.isFailedOrUnknownResolution()) { // Must mark the field as targeted even if it does not exist. - markFieldAsTargeted(field, currentMethod); + markFieldAsTargeted(fieldReference, currentMethod); return false; } - if (fromMethodHandle) { - fieldAccessInfoCollection.get(encodedField.field).setReadFromMethodHandle(); - } - - DexProgramClass holder = getProgramClassOrNull(encodedField.holder()); - if (holder == null) { + ProgramField field = + resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + if (field == null) { // No need to trace into the non-program code. return false; } + if (fromMethodHandle) { + fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle(); + } + if (Log.ENABLED) { - Log.verbose(getClass(), "Register Sget `%s`.", field); + Log.verbose(getClass(), "Register Sget `%s`.", fieldReference); } if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) { @@ -1266,22 +1298,21 @@ boolean skipTracing = appView.withGeneratedExtensionRegistryShrinker( shrinker -> - shrinker.isDeadProtoExtensionField( - encodedField, fieldAccessInfoCollection, pinnedItems), + shrinker.isDeadProtoExtensionField(field, fieldAccessInfoCollection, pinnedItems), false); if (skipTracing) { - addDeadProtoTypeCandidate(holder); + addDeadProtoTypeCandidate(field.getHolder()); return false; } } - if (encodedField.field != field) { + if (field.getReference() != fieldReference) { // Mark the non-rebound field access as targeted. Note that this should only be done if the // field is not a dead proto field (in which case we bail-out above). - markFieldAsTargeted(field, currentMethod); + markFieldAsTargeted(fieldReference, currentMethod); } - markStaticFieldAsLive(encodedField, KeepReason.fieldReferencedIn(currentMethod)); + markStaticFieldAsLive(field, KeepReason.fieldReferencedIn(currentMethod)); return true; } @@ -1294,30 +1325,31 @@ } private boolean traceStaticFieldWrite( - DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) { - if (!registerFieldWrite(field, currentMethod)) { + DexField fieldReference, ProgramMethod currentMethod, boolean fromMethodHandle) { + if (!registerFieldWrite(fieldReference, currentMethod)) { return false; } - DexEncodedField encodedField = resolveField(field); - if (encodedField == null) { + FieldResolutionResult resolutionResult = resolveField(fieldReference); + if (resolutionResult.isFailedOrUnknownResolution()) { // Must mark the field as targeted even if it does not exist. - markFieldAsTargeted(field, currentMethod); + markFieldAsTargeted(fieldReference, currentMethod); return false; } - if (fromMethodHandle) { - fieldAccessInfoCollection.get(encodedField.field).setWrittenFromMethodHandle(); - } - - DexProgramClass holder = getProgramClassOrNull(encodedField.holder()); - if (holder == null) { + ProgramField field = + resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField(); + if (field == null) { // No need to trace into the non-program code. return false; } + if (fromMethodHandle) { + fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle(); + } + if (Log.ENABLED) { - Log.verbose(getClass(), "Register Sput `%s`.", field); + Log.verbose(getClass(), "Register Sput `%s`.", fieldReference); } if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) { @@ -1325,22 +1357,21 @@ boolean skipTracing = appView.withGeneratedExtensionRegistryShrinker( shrinker -> - shrinker.isDeadProtoExtensionField( - encodedField, fieldAccessInfoCollection, pinnedItems), + shrinker.isDeadProtoExtensionField(field, fieldAccessInfoCollection, pinnedItems), false); if (skipTracing) { - addDeadProtoTypeCandidate(holder); + addDeadProtoTypeCandidate(field.getHolder()); return false; } } - if (encodedField.field != field) { + if (field.getReference() != fieldReference) { // Mark the non-rebound field access as targeted. Note that this should only be done if the // field is not a dead proto field (in which case we bail-out above). - markFieldAsTargeted(field, currentMethod); + markFieldAsTargeted(fieldReference, currentMethod); } - markStaticFieldAsLive(encodedField, KeepReason.fieldReferencedIn(currentMethod)); + markStaticFieldAsLive(field, KeepReason.fieldReferencedIn(currentMethod)); return true; } @@ -1505,7 +1536,8 @@ compatEnqueueHolderIfDependentNonStaticMember( holder, rootSet.getDependentKeepClassCompatRule(holder.getType())); - analyses.forEach(analysis -> analysis.processNewlyLiveClass(holder, workList)); + analyses.forEach( + analysis -> analysis.processNewlyLiveClass(holder, workList, enqueuerDefinitionSupplier)); } private void ensureMethodsContinueToWidenAccess(DexClass clazz) { @@ -1616,22 +1648,21 @@ annotation.annotation.collectIndexedItems(referenceMarker); } - private DexEncodedField resolveField(DexField field) { + private FieldResolutionResult resolveField(DexField field) { // Record the references in case they are not program types. recordTypeReference(field.holder); recordTypeReference(field.type); - DexEncodedField encodedField = appInfo.resolveField(field); - if (encodedField == null) { + FieldResolutionResult resolutionResult = appInfo.resolveField(field); + if (resolutionResult.isFailedOrUnknownResolution()) { reportMissingField(field); - return null; } - return encodedField; + return resolutionResult; } private SingleResolutionResult resolveMethod(DexMethod method, KeepReason reason) { // Record the references in case they are not program types. recordMethodReference(method); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method); if (resolutionResult.isFailedResolution()) { reportMissingMethod(method); markFailedResolutionTargets(method, resolutionResult.asFailedResolution(), reason); @@ -1643,8 +1674,7 @@ DexMethod method, KeepReason reason, boolean interfaceInvoke) { // Record the references in case they are not program types. recordMethodReference(method); - ResolutionResult resolutionResult = - appInfo.resolveMethod(method.holder, method, interfaceInvoke); + ResolutionResult resolutionResult = appInfo.resolveMethod(method, interfaceInvoke); if (resolutionResult.isFailedResolution()) { reportMissingMethod(method); markFailedResolutionTargets(method, resolutionResult.asFailedResolution(), reason); @@ -1998,7 +2028,7 @@ assert method.holder == superClass.type; if (seenMethods.add(MethodSignatureEquivalence.get().wrap(method))) { SingleResolutionResult resolution = - appInfo.resolveMethod(superClass, method).asSingleResolution(); + appInfo.resolveMethodOn(superClass, method).asSingleResolution(); assert resolution != null; assert resolution.getResolvedHolder().isProgramClass(); if (resolution != null && resolution.getResolvedHolder().isProgramClass()) { @@ -2052,7 +2082,7 @@ // Note: It would be reasonable to not process methods already seen during the marking of // program usages, but that would cause the methods to not be marked as library overrides. markLibraryOrClasspathOverrideLive( - instantiation, libraryClass, appInfo.resolveMethod(libraryClass, method.method)); + instantiation, libraryClass, appInfo.resolveMethodOn(libraryClass, method.method)); // Due to API conversion, some overrides can be hidden since they will be rewritten. See // class comment of DesugaredLibraryAPIConverter and vivifiedType logic. @@ -2068,7 +2098,7 @@ markLibraryOrClasspathOverrideLive( instantiation, libraryClass, - appInfo.resolveMethod(instantiation.asClass(), methodToResolve)); + appInfo.resolveMethodOn(instantiation.asClass(), methodToResolve)); } } } @@ -2123,12 +2153,11 @@ */ private void transitionFieldsForInstantiatedClass(DexProgramClass clazz) { do { - SetWithReason<DexEncodedField> reachableFields = reachableInstanceFields.get(clazz); + ProgramFieldSet reachableFields = reachableInstanceFields.get(clazz); if (reachableFields != null) { - for (DexEncodedField field : reachableFields.getItems()) { - // TODO(b/120959039): Should the reason this field is reachable come from the set? - markInstanceFieldAsLive(clazz, field, KeepReason.reachableFromLiveType(clazz.type)); - } + // TODO(b/120959039): Should the reason this field is reachable come from the set? + KeepReason reason = KeepReason.reachableFromLiveType(clazz.type); + reachableFields.forEach(field -> markInstanceFieldAsLive(field, reason)); } clazz = getProgramClassOrNull(clazz.superType); } while (clazz != null && !objectAllocationInfoCollection.isInstantiatedDirectly(clazz)); @@ -2176,58 +2205,48 @@ markTypeAsLive(field.holder, clazz -> graphReporter.reportClassReferencedFrom(clazz, context)); } - private void markStaticFieldAsLive(DexEncodedField encodedField, KeepReason reason) { + private void markStaticFieldAsLive(ProgramField field, KeepReason reason) { // Mark the type live here, so that the class exists at runtime. - DexField field = encodedField.field; markTypeAsLive( - field.holder, clazz -> graphReporter.reportClassReferencedFrom(clazz, encodedField)); + field.getHolder(), graphReporter.reportClassReferencedFrom(field.getHolder(), field)); markTypeAsLive( - field.type, clazz -> graphReporter.reportClassReferencedFrom(clazz, encodedField)); + field.getReference().type, clazz -> graphReporter.reportClassReferencedFrom(clazz, field)); - DexProgramClass clazz = getProgramClassOrNull(field.holder); - if (clazz == null) { - return; - } - - markDirectAndIndirectClassInitializersAsLive(clazz); + markDirectAndIndirectClassInitializersAsLive(field.getHolder()); // This field might be an instance field reachable from a static context, e.g. a getStatic that // resolves to an instance field. We have to keep the instance field nonetheless, as otherwise // we might unmask a shadowed static field and hence change semantics. - if (encodedField.accessFlags.isStatic()) { + if (field.getDefinition().isStatic()) { if (Log.ENABLED) { - Log.verbose(getClass(), "Adding static field `%s` to live set.", encodedField.field); + Log.verbose(getClass(), "Adding static field `%s` to live set.", field); } } else { if (Log.ENABLED) { - Log.verbose(getClass(), "Adding instance field `%s` to live set (static context).", - encodedField.field); + Log.verbose(getClass(), "Adding instance field `%s` to live set (static context).", field); } } - processAnnotations(clazz, encodedField); - liveFields.add(encodedField, reason); - - // Add all dependent members to the workqueue. - enqueueRootItems(rootSet.getDependentItems(encodedField)); - - // Notify analyses. - analyses.forEach(analysis -> analysis.processNewlyLiveField(encodedField)); - } - - private void markInstanceFieldAsLive( - DexProgramClass holder, DexEncodedField field, KeepReason reason) { - assert field != null; - assert field.isProgramField(appView); - markTypeAsLive(field.holder(), reason); - markTypeAsLive(field.field.type, reason); - if (Log.ENABLED) { - Log.verbose(getClass(), "Adding instance field `%s` to live set.", field.field); - } - processAnnotations(holder, field); + processAnnotations(field.getHolder(), field.getDefinition()); liveFields.add(field, reason); // Add all dependent members to the workqueue. - enqueueRootItems(rootSet.getDependentItems(field)); + enqueueRootItems(rootSet.getDependentItems(field.getDefinition())); + + // Notify analyses. + analyses.forEach(analysis -> analysis.processNewlyLiveField(field)); + } + + private void markInstanceFieldAsLive(ProgramField field, KeepReason reason) { + markTypeAsLive(field.getHolder(), graphReporter.registerClass(field.getHolder(), reason)); + markTypeAsLive(field.getReference().type, reason); + if (Log.ENABLED) { + Log.verbose(getClass(), "Adding instance field `%s` to live set.", field); + } + processAnnotations(field.getHolder(), field.getDefinition()); + liveFields.add(field, reason); + + // Add all dependent members to the workqueue. + enqueueRootItems(rootSet.getDependentItems(field.getDefinition())); // Notify analyses. analyses.forEach(analysis -> analysis.processNewlyLiveField(field)); @@ -2264,28 +2283,27 @@ return info != null; } - public boolean isFieldLive(DexEncodedField field) { + public boolean isFieldLive(ProgramField field) { return liveFields.contains(field); } - public boolean isFieldRead(DexEncodedField field) { - FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.field); + public boolean isFieldRead(ProgramField field) { + FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.getReference()); return info != null && info.isRead(); } public boolean isFieldWrittenInMethodSatisfying( - DexEncodedField field, Predicate<DexEncodedMethod> predicate) { - FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.field); + ProgramField field, Predicate<ProgramMethod> predicate) { + FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.getReference()); return info != null && info.isWrittenInMethodSatisfying(predicate); } - public boolean isFieldWrittenOutsideDefaultConstructor(DexEncodedField field) { - FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.field); + public boolean isFieldWrittenOutsideDefaultConstructor(ProgramField field) { + FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.getReference()); if (info == null) { return false; } - DexClass clazz = appView.definitionFor(field.holder()); - DexEncodedMethod defaultInitializer = clazz.getDefaultInitializer(); + DexEncodedMethod defaultInitializer = field.getHolder().getDefaultInitializer(); return defaultInitializer != null ? info.isWrittenOutside(defaultInitializer) : info.isWritten(); @@ -2322,37 +2340,30 @@ } // Package protected due to entry point from worklist. - void markInstanceFieldAsReachable(DexEncodedField encodedField, KeepReason reason) { - DexField field = encodedField.field; + void markInstanceFieldAsReachable(ProgramField field, KeepReason reason) { if (Log.ENABLED) { Log.verbose(getClass(), "Marking instance field `%s` as reachable.", field); } markTypeAsLive( - field.holder, clazz -> graphReporter.reportClassReferencedFrom(clazz, encodedField)); + field.getHolder(), graphReporter.reportClassReferencedFrom(field.getHolder(), field)); markTypeAsLive( - field.type, clazz -> graphReporter.reportClassReferencedFrom(clazz, encodedField)); - - DexProgramClass clazz = getProgramClassOrNull(field.holder); - if (clazz == null) { - return; - } + field.getReference().type, clazz -> graphReporter.reportClassReferencedFrom(clazz, field)); // We might have a instance field access that is dispatched to a static field. In such case, // we have to keep the static field, so that the dispatch fails at runtime in the same way that // it did before. We have to keep the field even if the receiver has no live inhabitants, as // field resolution happens before the receiver is inspected. - if (encodedField.accessFlags.isStatic()) { - markStaticFieldAsLive(encodedField, reason); + if (field.getDefinition().isStatic()) { + markStaticFieldAsLive(field, reason); + } else if (objectAllocationInfoCollection.isInstantiatedDirectlyOrHasInstantiatedSubtype( + field.getHolder())) { + markInstanceFieldAsLive(field, reason); } else { - if (objectAllocationInfoCollection.isInstantiatedDirectlyOrHasInstantiatedSubtype(clazz)) { - markInstanceFieldAsLive(clazz, encodedField, reason); - } else { - // Add the field to the reachable set if the type later becomes instantiated. - reachableInstanceFields - .computeIfAbsent(clazz, ignore -> newSetWithoutReasonReporter()) - .add(encodedField, reason); - } + // Add the field to the reachable set if the type later becomes instantiated. + reachableInstanceFields + .computeIfAbsent(field.getHolder(), ignore -> ProgramFieldSet.create()) + .add(field); } } @@ -2407,9 +2418,9 @@ DexEncodedMethod resolvedMethod = resolution.getResolvedMethod(); markMethodAsTargeted(new ProgramMethod(resolvedHolder, resolvedMethod), reason); - DexProgramClass context = contextOrNull == null ? null : contextOrNull.getHolder(); + DexProgramClass contextHolder = contextOrNull != null ? contextOrNull.getHolder() : null; if (contextOrNull != null - && resolution.isAccessibleForVirtualDispatchFrom(context, appInfo).isFalse()) { + && resolution.isAccessibleForVirtualDispatchFrom(contextHolder, appInfo).isFalse()) { // Not accessible from this context, so this call will cause a runtime exception. return; } @@ -2417,7 +2428,7 @@ // If the resolved method is not a virtual target, eg, is static, dispatch will fail too. if (!resolvedMethod.isVirtualMethod()) { // This can only happen when context is null, otherwise the access check above will fail. - assert context == null; + assert contextOrNull == null; return; } @@ -2426,7 +2437,7 @@ resolution .lookupVirtualDispatchTargets( - context, + contextHolder, appInfo, (type, subTypeConsumer, lambdaConsumer) -> objectAllocationInfoCollection.forEachInstantiatedSubType( @@ -2567,6 +2578,10 @@ throws ExecutionException { this.rootSet = rootSet; this.dontWarnPatterns = dontWarnPatterns; + if (!options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations + && mode.isInitialTreeShaking()) { + registerAnalysis(new KotlinMetadataEnqueuerExtension(appView)); + } // Translate the result of root-set computation into enqueuer actions. if (appView.options().isShrinking() || appView.options().getProguardConfiguration() == null) { enqueueRootItems(rootSet.noShrinking); @@ -2820,7 +2835,11 @@ new AppInfoWithLiveness( app, SetUtils.mapIdentityHashSet(deadProtoTypeCandidates, DexProgramClass::getType), - missingTypes, + // TODO(b/155959821): We should be able to assert that missing types is a subset of + // initialMissingTypes + synthesized types. + mode.isFinalTreeShaking() + ? Sets.union(initialMissingTypes, missingTypes) + : missingTypes, SetUtils.mapIdentityHashSet(liveTypes.getItems(), DexProgramClass::getType), Collections.unmodifiableSet(instantiatedAppServices), Enqueuer.toSortedDescriptorSet(targetedMethods.getItems()), @@ -3143,7 +3162,7 @@ private long getNumberOfLiveItems() { long result = liveTypes.items.size(); result += liveMethods.items.size(); - result += liveFields.items.size(); + result += liveFields.fields.size(); return result; } @@ -3281,12 +3300,11 @@ } // Package protected due to entry point from worklist. - void markFieldAsKept(DexProgramClass holder, DexEncodedField target, KeepReason reason) { - assert holder.type == target.holder(); - if (target.accessFlags.isStatic()) { - markStaticFieldAsLive(target, reason); + void markFieldAsKept(ProgramField field, KeepReason reason) { + if (field.getDefinition().isStatic()) { + markStaticFieldAsLive(field, reason); } else { - markInstanceFieldAsReachable(target, reason); + markInstanceFieldAsReachable(field, reason); } } @@ -3504,7 +3522,7 @@ if (clazz == null) { return; } - DexEncodedField encodedField = appView.definitionFor(field); + DexEncodedField encodedField = clazz.lookupField(field); if (encodedField == null) { return; } @@ -3514,14 +3532,14 @@ // fields since the creation of a field updater throws a NoSuchFieldException if the field // is not present. boolean keepClass = - !encodedField.accessFlags.isStatic() + !encodedField.isStatic() && dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(invokedMethod); if (keepClass) { workList.enqueueMarkInstantiatedAction( clazz, null, InstantiationReason.REFLECTION, KeepReason.reflectiveUseIn(method)); } if (pinnedItems.add(encodedField.field)) { - markFieldAsKept(clazz, encodedField, KeepReason.reflectiveUseIn(method)); + markFieldAsKept(new ProgramField(clazz, encodedField), KeepReason.reflectiveUseIn(method)); } } else { assert identifierItem.isDexMethod(); @@ -3817,6 +3835,32 @@ } } + private class LiveFieldsSet { + + private final Set<DexEncodedField> fields = Sets.newIdentityHashSet(); + + private final BiConsumer<DexEncodedField, KeepReason> register; + + LiveFieldsSet(BiConsumer<DexEncodedField, KeepReason> register) { + this.register = register; + } + + boolean add(ProgramField field, KeepReason reason) { + DexEncodedField definition = field.getDefinition(); + register.accept(definition, reason); + transitionUnusedInterfaceToLive(field.getHolder()); + return fields.add(definition); + } + + boolean contains(DexEncodedField field) { + return fields.contains(field); + } + + boolean contains(ProgramField field) { + return contains(field.getDefinition()); + } + } + private class LiveMethodsSet { private final Set<DexEncodedMethod> items = Sets.newIdentityHashSet(); @@ -3890,37 +3934,40 @@ } @Override - public boolean addField(DexField field) { - recordTypeReference(field.holder); - recordTypeReference(field.type); - DexClass holder = appView.definitionFor(field.holder); + public boolean addField(DexField fieldReference) { + recordFieldReference(fieldReference); + DexProgramClass holder = getProgramClassOrNull(fieldReference.holder); if (holder == null) { return false; } - DexEncodedField target = holder.lookupStaticField(field); - if (target != null) { - // There is no dispatch on annotations, so only keep what is directly referenced. - if (target.field == field) { - if (!registerFieldReadFromAnnotation(field)) { - return false; - } - markStaticFieldAsLive(target, KeepReason.referencedInAnnotation(annotationHolder)); - // When an annotation has a field of an enum type with a default value then Java VM - // will use the values() method on that enum class. - if (options.isGeneratingClassFiles() - && annotationHolder == dexItemFactory.annotationDefault) { - DexProgramClass clazz = getProgramClassOrNull(field.type); - if (clazz != null && clazz.accessFlags.isEnum()) { - markEnumValuesAsReachable(clazz, KeepReason.referencedInAnnotation(annotationHolder)); - } + ProgramField field = holder.lookupProgramField(fieldReference); + if (field == null) { + return false; + } + // There is no dispatch on annotations, so only keep what is directly referenced. + if (field.getReference() != fieldReference) { + return false; + } + if (field.getDefinition().isStatic()) { + FieldAccessInfoImpl fieldAccessInfo = + fieldAccessInfoCollection.contains(fieldReference) + ? fieldAccessInfoCollection.get(fieldReference) + : fieldAccessInfoCollection.extend( + fieldReference, new FieldAccessInfoImpl(fieldReference)); + fieldAccessInfo.setReadFromAnnotation(); + markStaticFieldAsLive(field, KeepReason.referencedInAnnotation(annotationHolder)); + // When an annotation has a field of an enum type with a default value then Java VM + // will use the values() method on that enum class. + if (options.isGeneratingClassFiles() + && annotationHolder == dexItemFactory.annotationDefault) { + if (field.getHolder().isEnum()) { + markEnumValuesAsReachable( + field.getHolder(), KeepReason.referencedInAnnotation(annotationHolder)); } } } else { - target = holder.lookupInstanceField(field); // There is no dispatch on annotations, so only keep what is directly referenced. - if (target != null && target.field != field) { - markInstanceFieldAsReachable(target, KeepReason.referencedInAnnotation(annotationHolder)); - } + markInstanceFieldAsReachable(field, KeepReason.referencedInAnnotation(annotationHolder)); } return false; } @@ -3984,4 +4031,44 @@ } } + public static class EnqueuerDefinitionSupplier implements DexDefinitionSupplier { + + private final Enqueuer enqueuer; + private final AppView<?> appView; + + private EnqueuerDefinitionSupplier(AppView<?> appView, Enqueuer enqueuer) { + this.appView = appView; + this.enqueuer = enqueuer; + } + + @Override + public DexDefinition definitionFor(DexReference reference) { + return enqueuer.definitionFor(reference); + } + + @Override + public DexEncodedField definitionFor(DexField field) { + return enqueuer.definitionFor(field); + } + + @Override + public DexEncodedMethod definitionFor(DexMethod method) { + return enqueuer.definitionFor(method); + } + + @Override + public DexClass definitionFor(DexType type) { + return enqueuer.definitionFor(type); + } + + @Override + public DexProgramClass definitionForProgramType(DexType type) { + return enqueuer.getProgramClassOrNull(type); + } + + @Override + public DexItemFactory dexItemFactory() { + return appView.dexItemFactory(); + } + } }
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java index f5ffc75..3c9649d 100644 --- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java +++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -5,11 +5,11 @@ package com.android.tools.r8.shaking; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness; import java.util.ArrayDeque; @@ -52,17 +52,17 @@ } static class MarkReachableFieldAction extends EnqueuerAction { - final DexEncodedField target; + final ProgramField field; final KeepReason reason; - public MarkReachableFieldAction(DexEncodedField target, KeepReason reason) { - this.target = target; + public MarkReachableFieldAction(ProgramField field, KeepReason reason) { + this.field = field; this.reason = reason; } @Override public void run(Enqueuer enqueuer) { - enqueuer.markInstanceFieldAsReachable(target, reason); + enqueuer.markInstanceFieldAsReachable(field, reason); } } @@ -151,20 +151,17 @@ } static class MarkFieldKeptAction extends EnqueuerAction { - final DexProgramClass holder; - final DexEncodedField target; + final ProgramField field; final KeepReasonWitness witness; - public MarkFieldKeptAction( - DexProgramClass holder, DexEncodedField target, KeepReasonWitness witness) { - this.holder = holder; - this.target = target; + public MarkFieldKeptAction(ProgramField field, KeepReasonWitness witness) { + this.field = field; this.witness = witness; } @Override public void run(Enqueuer enqueuer) { - enqueuer.markFieldAsKept(holder, target, witness); + enqueuer.markFieldAsKept(field, witness); } } @@ -255,9 +252,7 @@ queue.add(new MarkReachableSuperAction(method, from)); } - public void enqueueMarkReachableFieldAction( - DexProgramClass clazz, DexEncodedField field, KeepReason reason) { - assert field.holder() == clazz.type; + public void enqueueMarkReachableFieldAction(ProgramField field, KeepReason reason) { queue.add(new MarkReachableFieldAction(field, reason)); } @@ -293,10 +288,8 @@ queue.add(new MarkMethodKeptAction(method, reason)); } - void enqueueMarkFieldKeptAction( - DexProgramClass holder, DexEncodedField field, KeepReasonWitness witness) { - assert field.isProgramField(appView); - queue.add(new MarkFieldKeptAction(holder, field, witness)); + void enqueueMarkFieldKeptAction(ProgramField field, KeepReasonWitness witness) { + queue.add(new MarkFieldKeptAction(field, witness)); } public void enqueueTraceConstClassAction(DexType type, ProgramMethod context) {
diff --git a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java index 0e39b4c..2ab539d 100644 --- a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java +++ b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
@@ -26,6 +26,7 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter; import com.android.tools.r8.references.Reference; @@ -219,9 +220,9 @@ return KeepReasonWitness.INSTANCE; } - public KeepReasonWitness reportClassReferencedFrom(DexProgramClass clazz, DexEncodedField field) { + public KeepReasonWitness reportClassReferencedFrom(DexProgramClass clazz, ProgramField field) { if (keptGraphConsumer != null) { - FieldGraphNode source = getFieldGraphNode(field.field); + FieldGraphNode source = getFieldGraphNode(field.getReference()); ClassGraphNode target = getClassGraphNode(clazz.type); return reportEdge(source, target, EdgeKind.ReferencedFrom); }
diff --git a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java index f73139d..0979ef9 100644 --- a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java +++ b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
@@ -7,10 +7,10 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.TopDownClassHierarchyTraversal; import com.android.tools.r8.ir.analysis.escape.EscapeAnalysis; import com.android.tools.r8.ir.analysis.escape.EscapeAnalysisConfiguration; @@ -193,7 +193,7 @@ AppView<?> appView, EscapeAnalysis escapeAnalysis, Instruction escapeRoute, - DexMethod context) { + ProgramMethod context) { if (appView.appInfo().hasLiveness()) { return isLegitimateConstructorInvocation( appView.withLiveness(), escapeAnalysis, escapeRoute, context); @@ -205,7 +205,7 @@ AppView<AppInfoWithLiveness> appView, EscapeAnalysis escapeAnalysis, Instruction instruction, - DexMethod context) { + ProgramMethod context) { if (!instruction.isInvokeDirect()) { return false; } @@ -221,7 +221,7 @@ } } - DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context.holder); + DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context); if (singleTarget == null) { return false; }
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java index e105350..ffb940a 100644 --- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java +++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -378,7 +378,7 @@ // is due to the lack of the definition or it indeed means no matching rules. Similar to how // we apply those assume rules, here we use a resolved target. DexEncodedMethod target = - appView.appInfo().resolveMethod(subType, referenceInSubType).getSingleTarget(); + appView.appInfo().unsafeResolveMethodDueToDexFormat(referenceInSubType).getSingleTarget(); // But, the resolution should not be landed on the current type we are visiting. if (target == null || target.holder() == type) { continue; @@ -555,7 +555,7 @@ private void tryAndKeepMethodOnClass(DexEncodedMethod method, ProguardMemberRule rule) { SingleResolutionResult resolutionResult = - appView.appInfo().resolveMethod(originalClazz, method.method).asSingleResolution(); + appView.appInfo().resolveMethodOn(originalClazz, method.method).asSingleResolution(); if (resolutionResult == null || !resolutionResult.isVirtualTarget()) { return; } @@ -1286,6 +1286,10 @@ this.delayedRootSetActionItems = delayedRootSetActionItems; } + public boolean noShrinking(DexReference reference) { + return noShrinking.containsKey(reference); + } + public void forEachClassWithDependentItems( DexDefinitionSupplier definitions, Consumer<DexProgramClass> consumer) { for (DexReference reference : dependentNoShrinking.keySet()) {
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java index 31d8074..a540236 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -382,7 +382,7 @@ TraversalContinuation result = sourceClass.traverseProgramInstanceInitializers( method -> { - AbortReason reason = disallowInlining(method, targetClass.type); + AbortReason reason = disallowInlining(method, targetClass); if (reason != null) { // Cannot guarantee that markForceInline() will work. if (Log.ENABLED) { @@ -1182,7 +1182,7 @@ // Resolution would have succeeded if the method used to be in [type], or if one of // its super classes declared the method. boolean resolutionSucceededBeforeMerge = - renamedMembersLense.hasMappingForSignatureInContext(holder.type, signatureInType) + renamedMembersLense.hasMappingForSignatureInContext(holder, signatureInType) || appInfo.lookupSuperTarget(signatureInHolder, holder) != null; if (resolutionSucceededBeforeMerge) { deferredRenamings.mapVirtualMethodToDirectInType( @@ -1261,7 +1261,7 @@ // Returns the method that shadows the given method, or null if method is not shadowed. private DexEncodedMethod findMethodInTarget(DexEncodedMethod method) { - ResolutionResult resolutionResult = appInfo.resolveMethod(target, method.method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(target, method.method); if (!resolutionResult.isSingleResolution()) { // May happen in case of missing classes, or if multiple implementations were found. abortMerge = true; @@ -1655,7 +1655,7 @@ } } - private AbortReason disallowInlining(ProgramMethod method, DexType invocationContext) { + private AbortReason disallowInlining(ProgramMethod method, DexProgramClass context) { if (appView.options().enableInlining) { Code code = method.getDefinition().getCode(); if (code.isCfCode()) { @@ -1664,14 +1664,14 @@ cfCode.computeInliningConstraint( method, appView, - new SingleTypeMapperGraphLense(method.getHolderType(), invocationContext), - invocationContext); + new SingleTypeMapperGraphLense(method.getHolderType(), context), + context); if (constraint == ConstraintWithTarget.NEVER) { return AbortReason.UNSAFE_INLINING; } // Constructors can have references beyond the root main dex classes. This can increase the // size of the main dex dependent classes and we should bail out. - if (mainDexClasses.getRoots().contains(invocationContext) + if (mainDexClasses.getRoots().contains(context.type) && MainDexDirectReferenceTracer.hasReferencesOutsideFromCode( appView.appInfo(), method, mainDexClasses.getRoots())) { return AbortReason.MAIN_DEX_ROOT_OUTSIDE_REFERENCE; @@ -1686,9 +1686,9 @@ private class SingleTypeMapperGraphLense extends GraphLense { private final DexType source; - private final DexType target; + private final DexProgramClass target; - public SingleTypeMapperGraphLense(DexType source, DexType target) { + public SingleTypeMapperGraphLense(DexType source, DexProgramClass target) { this.source = source; this.target = target; } @@ -1720,7 +1720,7 @@ @Override public DexType lookupType(DexType type) { - return type == source ? target : mergedClasses.getOrDefault(type, type); + return type == source ? target.type : mergedClasses.getOrDefault(type, type); } @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java index 1013539..1202384 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
@@ -8,6 +8,7 @@ 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.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLense; @@ -303,9 +304,9 @@ return mergedClasses.getOrDefault(type, type); } - public boolean hasMappingForSignatureInContext(DexType context, DexMethod signature) { + public boolean hasMappingForSignatureInContext(DexProgramClass context, DexMethod signature) { Map<DexMethod, GraphLenseLookupResult> virtualToDirectMethodMap = - contextualVirtualToDirectMethodMaps.get(context); + contextualVirtualToDirectMethodMaps.get(context.type); if (virtualToDirectMethodMap != null) { return virtualToDirectMethodMap.containsKey(signature); }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java index 60b6f7d..f15c049 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -41,9 +41,9 @@ O_MR1(27), P(28), Q(29), - R(30); // Speculative, this can change. + R(30); - public static final AndroidApiLevel LATEST = Q; + public static final AndroidApiLevel LATEST = R; public static final int magicApiLevelUsedByAndroidPlatformBuild = 10000;
diff --git a/src/main/java/com/android/tools/r8/utils/BooleanBox.java b/src/main/java/com/android/tools/r8/utils/BooleanBox.java index d31e352..f46ac1c 100644 --- a/src/main/java/com/android/tools/r8/utils/BooleanBox.java +++ b/src/main/java/com/android/tools/r8/utils/BooleanBox.java
@@ -18,7 +18,15 @@ return value; } + public void set() { + set(true); + } + public void set(boolean value) { this.value = value; } + + public void unset() { + set(false); + } }
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java index 99098d8..e9557fa 100644 --- a/src/main/java/com/android/tools/r8/utils/DexVersion.java +++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -38,6 +38,7 @@ public static DexVersion getDexVersion(AndroidApiLevel androidApiLevel) { switch (androidApiLevel) { + case R: case Q: case P: return DexVersion.V39;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java index 62aa29a..e92effc 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -73,6 +73,7 @@ import java.util.function.BiConsumer; import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.objectweb.asm.Opcodes; @@ -838,14 +839,14 @@ } public void warningMissingTypeForDesugar( - Origin origin, Position position, DexType missingType, DexType contextType) { + Origin origin, Position position, DexType missingType, DexMethod context) { if (reportedMissingForDesugaring.add(missingType)) { reporter.warning( new InterfaceDesugarMissingTypeDiagnostic( origin, position, Reference.classFromDescriptor(missingType.toDescriptorString()), - Reference.classFromDescriptor(contextType.toDescriptorString()), + Reference.classFromDescriptor(context.holder.toDescriptorString()), null)); } } @@ -1186,6 +1187,8 @@ } public Consumer<ProgramMethod> callSiteOptimizationInfoInspector = null; + + public Predicate<DexEncodedMethod> cfByteCodePassThrough = null; } @VisibleForTesting
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java index 8cdce08..d62402b 100644 --- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java +++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -338,7 +338,9 @@ optimizeDexCodePositions( method, appView, kotlinRemapper, mappedPositions, identityMapping); } - } else if (code.isCfCode() && doesContainPositions(code.asCfCode())) { + } else if (code.isCfCode() + && doesContainPositions(code.asCfCode()) + && !appView.isCfByteCodePassThrough(method)) { optimizeCfCodePositions(method, kotlinRemapper, mappedPositions, appView); } }
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramMethodEquivalence.java b/src/main/java/com/android/tools/r8/utils/ProgramMethodEquivalence.java new file mode 100644 index 0000000..91553b8 --- /dev/null +++ b/src/main/java/com/android/tools/r8/utils/ProgramMethodEquivalence.java
@@ -0,0 +1,29 @@ +// Copyright (c) 2020, 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.utils; + +import com.android.tools.r8.graph.ProgramMethod; +import com.google.common.base.Equivalence; + +public class ProgramMethodEquivalence extends Equivalence<ProgramMethod> { + + private static final ProgramMethodEquivalence INSTANCE = new ProgramMethodEquivalence(); + + private ProgramMethodEquivalence() {} + + public static ProgramMethodEquivalence get() { + return INSTANCE; + } + + @Override + protected boolean doEquivalent(ProgramMethod method, ProgramMethod other) { + return method.getDefinition() == other.getDefinition(); + } + + @Override + protected int doHash(ProgramMethod method) { + return method.getReference().hashCode(); + } +}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramFieldSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramFieldSet.java new file mode 100644 index 0000000..5a9e280 --- /dev/null +++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramFieldSet.java
@@ -0,0 +1,99 @@ +// Copyright (c) 2020, 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.utils.collections; + +import com.android.tools.r8.graph.DexEncodedField; +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramField; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public class ProgramFieldSet implements Iterable<ProgramField> { + + private static final ProgramFieldSet EMPTY = new ProgramFieldSet(ImmutableMap.of()); + + private Map<DexField, ProgramField> backing; + + private ProgramFieldSet(Map<DexField, ProgramField> backing) { + this.backing = backing; + } + + public static ProgramFieldSet create() { + return new ProgramFieldSet(new IdentityHashMap<>()); + } + + public static ProgramFieldSet empty() { + return EMPTY; + } + + public boolean add(ProgramField field) { + ProgramField existing = backing.put(field.getReference(), field); + assert existing == null || existing.isStructurallyEqualTo(field); + return existing == null; + } + + public void addAll(Iterable<ProgramField> fields) { + fields.forEach(this::add); + } + + public void addAll(ProgramFieldSet fields) { + backing.putAll(fields.backing); + } + + public boolean createAndAdd(DexProgramClass clazz, DexEncodedField definition) { + return add(new ProgramField(clazz, definition)); + } + + public boolean contains(DexEncodedField field) { + return backing.containsKey(field.toReference()); + } + + public boolean contains(ProgramField field) { + return backing.containsKey(field.getReference()); + } + + public void clear() { + backing.clear(); + } + + public boolean isEmpty() { + return backing.isEmpty(); + } + + @Override + public Iterator<ProgramField> iterator() { + return backing.values().iterator(); + } + + public boolean remove(DexField field) { + ProgramField existing = backing.remove(field); + return existing != null; + } + + public boolean remove(DexEncodedField field) { + return remove(field.toReference()); + } + + public int size() { + return backing.size(); + } + + public Stream<ProgramField> stream() { + return backing.values().stream(); + } + + public Set<DexEncodedField> toDefinitionSet() { + assert backing instanceof IdentityHashMap; + Set<DexEncodedField> definitions = Sets.newIdentityHashSet(); + forEach(field -> definitions.add(field.getDefinition())); + return definitions; + } +}
diff --git a/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java b/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java index d881974..2ae20c9 100644 --- a/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java +++ b/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
@@ -352,18 +352,18 @@ return descriptorList; } - private static byte[] getClassAsBytes(ArchiveClassFileProvider inputJar, String descriptor) + public static byte[] getClassAsBytes(ClassFileResourceProvider inputJar, String descriptor) throws Exception { return toByteArray(inputJar.getProgramResource(descriptor).getByteStream()); } - private static String asmToString(byte[] clazz) { + public static String asmToString(byte[] clazz) { StringWriter stringWriter = new StringWriter(); printAsm(new PrintWriter(stringWriter), clazz); return stringWriter.toString(); } - private static void printAsm(PrintWriter pw, byte[] clazz) { + public static void printAsm(PrintWriter pw, byte[] clazz) { new ClassReader(clazz).accept(new TraceClassVisitor(null, new ASMifierSorted(), pw), 0); }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java index 7938666..000ffbc 100644 --- a/src/test/java/com/android/tools/r8/TestBase.java +++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -33,6 +33,7 @@ import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.DirectMappedDexApplication; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.SmaliWriter; import com.android.tools.r8.graph.SubtypingInfo; import com.android.tools.r8.jasmin.JasminBuilder; @@ -1294,13 +1295,14 @@ return getMethodSubject(application, className, returnType, methodName, parameters).getMethod(); } - protected DexEncodedMethod getMethod( + protected ProgramMethod getMethod( CodeInspector inspector, String className, String returnType, String methodName, List<String> parameters) { - return getMethodSubject(inspector, className, returnType, methodName, parameters).getMethod(); + return getMethodSubject(inspector, className, returnType, methodName, parameters) + .getProgramMethod(); } protected static void checkInstructions(
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java index 7ea2765..3efb9b1 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java
@@ -15,10 +15,7 @@ import com.android.tools.r8.utils.codeinspector.FieldSubject; import org.junit.Test; -/** - * Tests that both R8 and Proguard may change the visibility of a field or method that is explicitly - * kept. - */ +/** Tests that Proguard may change the visibility of a field or method that is explicitly kept. */ public class AccessRelaxationProguardCompatTest extends TestBase { private static Class<?> clazz = AccessRelaxationProguardCompatTestClass.class; @@ -35,7 +32,7 @@ "}") .allowAccessModification() .compile() - .inspect(AccessRelaxationProguardCompatTest::inspect); + .inspect(inspector -> inspect(inspector, true)); } @Test @@ -49,10 +46,10 @@ "}") .allowAccessModification() .compile() - .inspect(AccessRelaxationProguardCompatTest::inspect); + .inspect(inspector -> inspect(inspector, false)); } - private static void inspect(CodeInspector inspector) { + private static void inspect(CodeInspector inspector, boolean isR8) { ClassSubject classSubject = inspector.clazz(clazzWithGetter); assertThat(classSubject, isPresent()); @@ -60,7 +57,11 @@ assertThat(fieldSubject, isPresent()); // Although this field was explicitly kept, it is no longer private. - assertThat(fieldSubject, not(isPrivate())); + if (isR8) { + assertThat(fieldSubject, isPrivate()); + } else { + assertThat(fieldSubject, not(isPrivate())); + } } }
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PrivateKeptMembersPublicizerTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PrivateKeptMembersPublicizerTest.java new file mode 100644 index 0000000..940479a --- /dev/null +++ b/src/test/java/com/android/tools/r8/accessrelaxation/PrivateKeptMembersPublicizerTest.java
@@ -0,0 +1,67 @@ +// Copyright (c) 2020, 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.accessrelaxation; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class PrivateKeptMembersPublicizerTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public PrivateKeptMembersPublicizerTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(PrivateKeptMembersPublicizerTest.class) + .addKeepClassAndMembersRules(TestClass.class) + .allowAccessModification() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect(this::inspect) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("Hello world!"); + } + + private void inspect(CodeInspector inspector) { + ClassSubject classSubject = inspector.clazz(TestClass.class); + assertThat(classSubject, isPresent()); + assertTrue(classSubject.uniqueFieldWithName("greeting").isPrivate()); + assertTrue(classSubject.uniqueMethodWithName("greet").isPrivate()); + } + + static class TestClass { + + private static String greeting = "Hello world!"; + + public static void main(String[] args) { + greet(greeting); + } + + private static void greet(String message) { + System.out.println(message); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java index de3afb5..c27b55b 100644 --- a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
@@ -73,7 +73,7 @@ // } AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory()); - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method); DexType typeI = buildType(I.class, appView.dexItemFactory()); DexType typeL = buildType(L.class, appView.dexItemFactory()); DexType typeA = buildType(A.class, appView.dexItemFactory()); @@ -114,7 +114,7 @@ // } AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory()); - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method); DexType typeI = buildType(I.class, appView.dexItemFactory()); DexType typeL = buildType(L.class, appView.dexItemFactory()); DexType typeA = buildType(A.class, appView.dexItemFactory()); @@ -154,7 +154,7 @@ // } AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(J.class, J.class); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory()); - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method); DexType typeI = buildType(I.class, appView.dexItemFactory()); DexType typeB = buildType(A.class, appView.dexItemFactory()); DexProgramClass classI = appView.definitionForProgramType(typeI); @@ -191,7 +191,7 @@ // } AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(J.class, A.class); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory()); - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method); DexType typeI = buildType(I.class, appView.dexItemFactory()); DexType typeB = buildType(A.class, appView.dexItemFactory()); DexProgramClass classI = appView.definitionForProgramType(typeI); @@ -230,7 +230,7 @@ // } AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory()); - ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method); DexType typeI = buildType(I.class, appView.dexItemFactory()); DexType typeB = buildType(A.class, appView.dexItemFactory()); DexProgramClass classI = appView.definitionForProgramType(typeI);
diff --git a/src/test/java/com/android/tools/r8/code/PassThroughTest.java b/src/test/java/com/android/tools/r8/code/PassThroughTest.java new file mode 100644 index 0000000..b1a9f2f --- /dev/null +++ b/src/test/java/com/android/tools/r8/code/PassThroughTest.java
@@ -0,0 +1,160 @@ +// Copyright (c) 2020, 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.code; + +import static junit.framework.Assert.assertSame; + +import com.android.tools.r8.ArchiveClassFileProvider; +import com.android.tools.r8.CfFrontendExamplesTest; +import com.android.tools.r8.ClassFileResourceProvider; +import com.android.tools.r8.DirectoryClassFileProvider; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestShrinkerBuilder; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.StringUtils; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class PassThroughTest extends TestBase { + + private final String EXPECTED = StringUtils.lines("0", "foo", "0"); + + private final TestParameters parameters; + private final boolean keepDebug; + + @Parameters(name = "{0}, keep-debug: {1}") + public static List<Object[]> data() { + return buildParameters(getTestParameters().withCfRuntimes().build(), BooleanUtils.values()); + } + + public PassThroughTest(TestParameters parameters, boolean keepDebug) { + this.parameters = parameters; + this.keepDebug = keepDebug; + } + + @Test + public void testJmv() throws Exception { + CodeInspector inspector = + testForJvm() + .addProgramClasses(Main.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED) + .inspector(); + // Check that reading the same input is actual matches. + ClassFileResourceProvider original = + DirectoryClassFileProvider.fromDirectory(ToolHelper.getClassPathForTests()); + verifyInstructionsForMainMatchingExpectation(original, true, true); + } + + @Test + public void testR8() throws Exception { + Path outputJar = temp.newFile("output.jar").toPath(); + testForR8(parameters.getBackend()) + .addProgramClasses(Main.class) + .addKeepMainRule(Main.class) + .ifTrue(keepDebug, TestShrinkerBuilder::addKeepAllAttributes) + .compile() + .writeToZip(outputJar) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + verifyInstructionsForMainMatchingExpectation( + new ArchiveClassFileProvider(outputJar), keepDebug, false); + } + + @Test + public void testR8ByteCodePassThrough() throws Exception { + Path outputJar = temp.newFile("output.jar").toPath(); + testForR8(parameters.getBackend()) + .addProgramClasses(Main.class) + .addKeepMainRule(Main.class) + .ifTrue(keepDebug, TestShrinkerBuilder::addKeepAllAttributes) + .addOptionsModification( + internalOptions -> + internalOptions.testing.cfByteCodePassThrough = + method -> method.method.name.toString().equals("main")) + .compile() + .writeToZip(outputJar) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + verifyInstructionsForMainMatchingExpectation( + new ArchiveClassFileProvider(outputJar), keepDebug, true); + } + + private void verifyInstructionsForMainMatchingExpectation( + ClassFileResourceProvider actual, boolean checkDebug, boolean expectation) throws Exception { + ClassFileResourceProvider original = + DirectoryClassFileProvider.fromDirectory(ToolHelper.getClassPathForTests()); + String descriptor = DescriptorUtils.javaTypeToDescriptor(Main.class.getTypeName()); + byte[] expectedBytes = CfFrontendExamplesTest.getClassAsBytes(original, descriptor); + byte[] actualBytes = CfFrontendExamplesTest.getClassAsBytes(actual, descriptor); + if (!Arrays.equals(expectedBytes, actualBytes)) { + String expectedString = CfFrontendExamplesTest.asmToString(expectedBytes); + String actualString = CfFrontendExamplesTest.asmToString(actualBytes); + verifyInstructionsForMainMatchingExpectation( + getMethodInstructions(expectedString), + getMethodInstructions(actualString), + checkDebug, + expectation); + } + } + + private String getMethodInstructions(String asm) { + int methodIndexStart = + asm.indexOf( + "methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, \"main\"," + + " \"([Ljava/lang/String;)V\", null, null);"); + int methodIndexEnd = asm.indexOf("}", methodIndexStart); + return asm.substring(methodIndexStart, methodIndexEnd); + } + + private void verifyInstructionsForMainMatchingExpectation( + String originalInstructions, + String actualInstructions, + boolean checkDebug, + boolean expectation) { + if (!checkDebug) { + originalInstructions = + StringUtils.splitLines(originalInstructions).stream() + .filter(this::isNotDebugInstruction) + .map(instr -> instr + "\n") + .collect(Collectors.joining()); + } + assertSame(expectation, actualInstructions.equals(originalInstructions)); + } + + private boolean isNotDebugInstruction(String instruction) { + return !(instruction.startsWith("methodVisitor.visitLocalVariable") + || instruction.startsWith("methodVisitor.visitLabel") + || instruction.startsWith("Label") + || instruction.startsWith("methodVisitor.visitLineNumber")); + } + + public static class Main { + + public static void main(String[] args) { + int i = 0; + System.out.println(i); + int j = 0; + String foo = "foo"; + // Keep the false to have R8 remove it. + if (false) { + System.out.println(foo); + } + System.out.println(foo); + System.out.println(j); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java index 5dac547..e9d9d79 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -6,18 +6,16 @@ import static org.hamcrest.core.StringContains.containsString; +import com.android.tools.r8.D8TestRunResult; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper.DexVm.Version; import com.android.tools.r8.utils.AndroidApiLevel; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; @RunWith(Parameterized.class) public class ApiLevelBackportsTest extends TestBase { @@ -26,6 +24,8 @@ @Parameterized.Parameters(name = "{0}") public static TestParametersCollection data() { + // NOTE: Most of the 'run' invocations below work only because the static configured APIs do not + // give rise to DEX file versions larger than what can be accepted by VM 9.0.0. return getTestParameters().withDexRuntimesStartingFromIncluding(Version.V9_0_0).build(); } @@ -36,22 +36,49 @@ @Test public void backportSucceedsOnSupportedApiLevel() throws Exception { testForD8() - .addProgramClassFileData(Dump.mainWithMathMultiplyExactLongInt()) + .addProgramClassFileData(transformTestMathMultiplyExactLongInt()) .setMinApi(AndroidApiLevel.B) - .run(parameters.getRuntime(), "Test") + .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class) .assertSuccessWithOutputLines("4"); } @Test - public void warningForNonPlatformBuild() throws Exception { + public void backportOfNonPresentMethodOnLatest() throws Exception { testForD8() - .addProgramClassFileData(Dump.mainWithMathMultiplyExactLongInt()) - .setMinApi(30) + .addProgramClassFileData(transformTestMathMultiplyExactLongInt()) + .setMinApi(AndroidApiLevel.LATEST) + .compile() + .assertNoMessages() + .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class) + .assertSuccessWithOutputLines("4"); + } + + @Test + public void backportOfPresentMethodOnLatest() throws Exception { + D8TestRunResult result = + testForD8() + .addProgramClassFileData(transformTestListOf()) + .setMinApi(AndroidApiLevel.LATEST) + .compile() + .assertNoMessages() + .run(parameters.getRuntime(), TestListOf.class); + if (runtimeHasListOf()) { + result.assertSuccessWithOutputLines("0"); + } else { + result.assertFailureWithErrorThatMatches( + containsString("java.lang.NoSuchMethodError: No static method of()Ljava/util/List;")); + } + } + + @Test + public void warningForFutureNonPlatformBuild() throws Exception { + testForD8() + .addProgramClassFileData(transformTestMathMultiplyExactLongInt()) + .setMinApi(AndroidApiLevel.LATEST.getLevel() + 1) .compile() .assertOnlyWarnings() - .assertWarningMessageThatMatches( - containsString("An API level of 30 is not supported by this compiler")) - .run(parameters.getRuntime(), "Test") + .assertWarningMessageThatMatches(containsString("is not supported by this compiler")) + .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class) .assertFailureWithErrorThatMatches( containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J")); } @@ -59,70 +86,78 @@ @Test public void noWarningForPlatformBuild() throws Exception { testForD8() - .addProgramClassFileData(Dump.mainWithMathMultiplyExactLongInt()) + .addProgramClassFileData(transformTestMathMultiplyExactLongInt()) .setMinApi(AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild) - .run(parameters.getRuntime(), "Test") + .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class) .assertFailureWithErrorThatMatches( containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J")); } - static class Dump implements Opcodes { + // Test class for using: List List.of() + // Introduced in Android R. - // Code for: - // - // class Test { - // public static void main(String[] args) { - // // Call Math.multiplyExact(long, int), which is not in Android Q. - // System.out.println(Math.multiplyExact(2L, 2)); - // } - // } - // - static byte[] mainWithMathMultiplyExactLongInt() { + boolean runtimeHasListOf() { + return parameters + .getRuntime() + .asDex() + .getMinApiLevel() + .isGreaterThanOrEqualTo(AndroidApiLevel.R); + } - ClassWriter classWriter = new ClassWriter(0); - MethodVisitor methodVisitor; + byte[] transformTestListOf() throws Exception { + return transformer(TestListOf.class) + .transformMethodInsnInMethod( + "main", + (opcode, owner, name, descriptor, isInterface, visitor) -> { + if (name.equals("List_of")) { + visitor.visitMethodInsn(opcode, "java/util/List", "of", descriptor, isInterface); + } else { + visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + }) + .transform(); + } - classWriter.visit(V1_8, ACC_SUPER, "Test", null, "java/lang/Object", null); + static class TestListOf { + public static List List_of() { + throw null; + } - classWriter.visitSource("Test.java", null); + public static void main(String[] args) { + System.out.println(List_of().size()); + } + } - { - methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null); - methodVisitor.visitCode(); - Label label0 = new Label(); - methodVisitor.visitLabel(label0); - methodVisitor.visitLineNumber(1, label0); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); - methodVisitor.visitInsn(RETURN); - methodVisitor.visitMaxs(1, 1); - methodVisitor.visitEnd(); - } - { - methodVisitor = - classWriter.visitMethod( - ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); - methodVisitor.visitCode(); - Label label0 = new Label(); - methodVisitor.visitLabel(label0); - methodVisitor.visitLineNumber(3, label0); - methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - methodVisitor.visitLdcInsn(Long.valueOf(2L)); - methodVisitor.visitLdcInsn(Integer.valueOf(2)); - methodVisitor.visitMethodInsn( - INVOKESTATIC, "java/lang/Math", "multiplyExact", "(JI)J", false); - methodVisitor.visitMethodInsn( - INVOKEVIRTUAL, "java/io/PrintStream", "println", "(J)V", false); - Label label1 = new Label(); - methodVisitor.visitLabel(label1); - methodVisitor.visitLineNumber(4, label1); - methodVisitor.visitInsn(RETURN); - methodVisitor.visitMaxs(5, 1); - methodVisitor.visitEnd(); - } - classWriter.visitEnd(); + // Test class for the method: long Math.multiplyExact(long, int) + // Not present on any currently known Android platforms. - return classWriter.toByteArray(); + boolean runtimeHasMathMultiplyExactLongInt() { + // NOTE: This may change with a future release. + return false; + } + + byte[] transformTestMathMultiplyExactLongInt() throws Exception { + return transformer(TestMathMultiplyExactLongInt.class) + .transformMethodInsnInMethod( + "main", + (opcode, owner, name, descriptor, isInterface, visitor) -> { + if (name.equals("Math_multiplyExact")) { + visitor.visitMethodInsn( + opcode, "java/lang/Math", "multiplyExact", descriptor, isInterface); + } else { + visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + }) + .transform(); + } + + static class TestMathMultiplyExactLongInt { + public static long Math_multiplyExact(long l, int i) { + throw null; + } + + public static void main(String[] args) { + System.out.println(Math_multiplyExact(2L, 2)); } } }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java new file mode 100644 index 0000000..8dd0d27 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
@@ -0,0 +1,71 @@ +// Copyright (c) 2020, 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.desugar.desugaredlibrary; + +import com.android.tools.r8.CompilationMode; +import com.android.tools.r8.L8Command; +import com.android.tools.r8.OutputMode; +import com.android.tools.r8.StringResource; +import com.android.tools.r8.TestDiagnosticMessagesImpl; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.BooleanUtils; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class DesugaredLibraryWarningTest extends DesugaredLibraryTestBase { + + private static final String FUNCTION_KEEP = + "-keep class j$.util.function.Function$-CC {\n" + + " j$.util.function.Function $default$compose(j$.util.function.Function," + + " j$.util.function.Function);\n" + + " j$.util.function.Function $default$andThen(j$.util.function.Function," + + " j$.util.function.Function);\n" + + "}\n" + + "-keep class j$.util.function.Function { *; }"; + + private final TestParameters parameters; + private final boolean shrinkDesugaredLibrary; + + @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}") + public static List<Object[]> data() { + return buildParameters( + BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build()); + } + + public DesugaredLibraryWarningTest(boolean shrinkDesugaredLibrary, TestParameters parameters) { + this.shrinkDesugaredLibrary = shrinkDesugaredLibrary; + this.parameters = parameters; + } + + @Test + public void testDesugaredLibraryContent() throws Exception { + TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl(); + Path desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs_dex.zip"); + L8Command.Builder l8Builder = + L8Command.builder(diagnosticsHandler) + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) + .addProgramFiles(ToolHelper.getDesugarJDKLibs()) + .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS) + .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG) + .addDesugaredLibraryConfiguration( + StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) + .setMinApiLevel(parameters.getApiLevel().getLevel()) + .setOutput(desugaredLib, OutputMode.DexIndexed); + if (shrinkDesugaredLibrary) { + l8Builder.addProguardConfiguration( + Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown()); + } + ToolHelper.runL8(l8Builder.build(), options -> {}); + diagnosticsHandler.assertNoMessages(); + } +}
diff --git a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java index 945f3c2..71d5ffb 100644 --- a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java +++ b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
@@ -25,6 +25,7 @@ import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.codeinspector.CodeInspector; @@ -127,13 +128,15 @@ .addDexProgramData(Files.toByteArray(originalDexFile.toFile()), Origin.unknown()) .build(); CodeInspector inspector = new CodeInspector(application); - DexEncodedMethod method = getMethod( - inspector, - "android.databinding.DataBinderMapperImpl", - "android.databinding.ViewDataBinding", - "getDataBinder", - ImmutableList.of("android.databinding.DataBindingComponent", "android.view.View", "int")); - Instruction[] instructions = method.getCode().asDexCode().instructions; + ProgramMethod method = + getMethod( + inspector, + "android.databinding.DataBinderMapperImpl", + "android.databinding.ViewDataBinding", + "getDataBinder", + ImmutableList.of( + "android.databinding.DataBindingComponent", "android.view.View", "int")); + Instruction[] instructions = method.getDefinition().getCode().asDexCode().instructions; assertEquals(0, countJumboStrings(instructions)); assertEquals(1, countSimpleNops(instructions));
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java index 8524677..9c86160 100644 --- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java +++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -80,12 +80,11 @@ AndroidApp application = buildApplication(builder); AppInfoWithClassHierarchy appInfo = computeAppInfoWithClassHierarchy(application); CodeInspector inspector = new CodeInspector(appInfo.app()); - DexEncodedMethod method = getMethod(inspector, DEFAULT_CLASS_NAME, "int", "x", - ImmutableList.of()); + ProgramMethod method = getMethod(inspector, DEFAULT_CLASS_NAME, "int", "x", ImmutableList.of()); assertFalse( - appInfo.resolveMethod(method.holder(), method.method).getSingleTarget().isVirtualMethod()); - assertNull(appInfo.lookupDirectTarget(method.method, method.holder())); - assertNotNull(appInfo.lookupStaticTarget(method.method, method.holder())); + appInfo.resolveMethodOnClass(method.getReference()).getSingleTarget().isVirtualMethod()); + assertNull(appInfo.lookupDirectTarget(method.getReference(), method)); + assertNotNull(appInfo.lookupStaticTarget(method.getReference(), method)); if (ToolHelper.getDexVm().getVersion().isOlderThanOrEqual(DexVm.Version.V4_4_4)) { // Dalvik rejects at verification time instead of producing the @@ -152,32 +151,35 @@ AppInfoWithClassHierarchy appInfo = computeAppInfoWithClassHierarchy(application); CodeInspector inspector = new CodeInspector(appInfo.app()); - DexMethod methodXOnTestSuper = - getMethod(inspector, "TestSuper", "int", "x", ImmutableList.of()).method; - DexMethod methodYOnTest = - getMethod(inspector, "Test", "int", "y", ImmutableList.of()).method; + ProgramMethod methodXOnTestSuper = + getMethod(inspector, "TestSuper", "int", "x", ImmutableList.of()); + ProgramMethod methodYOnTest = getMethod(inspector, "Test", "int", "y", ImmutableList.of()); - DexType classTestSuper = methodXOnTestSuper.holder; - DexType classTest = methodYOnTest.holder; - DexProto methodXProto = methodXOnTestSuper.proto; - DexString methodXName = methodXOnTestSuper.name; - DexMethod methodXOnTest = + DexType classTestSuper = methodXOnTestSuper.getHolderType(); + DexType classTest = methodYOnTest.getHolderType(); + DexProto methodXProto = methodXOnTestSuper.getReference().proto; + DexString methodXName = methodXOnTestSuper.getReference().name; + DexMethod methodXOnTestReference = appInfo.dexItemFactory().createMethod(classTest, methodXProto, methodXName); assertFalse( appInfo - .resolveMethod(classTestSuper, methodXOnTestSuper) + .resolveMethodOnClass(methodXOnTestSuper.getReference(), classTestSuper) .getSingleTarget() .isVirtualMethod()); - assertNull(appInfo.resolveMethod(classTest, methodXOnTestSuper).getSingleTarget()); - assertNull(appInfo.resolveMethod(classTest, methodXOnTest).getSingleTarget()); + assertNull( + appInfo + .resolveMethodOnClass(methodXOnTestSuper.getReference(), classTest) + .getSingleTarget()); + assertNull(appInfo.resolveMethodOnClass(methodXOnTestReference, classTest).getSingleTarget()); - assertNull(appInfo.lookupDirectTarget(methodXOnTestSuper, methodXOnTestSuper.holder)); - assertNull(appInfo.lookupDirectTarget(methodXOnTest, methodXOnTest.holder)); + assertNull(appInfo.lookupDirectTarget(methodXOnTestSuper.getReference(), methodXOnTestSuper)); + assertNull(appInfo.lookupDirectTarget(methodXOnTestReference, methodYOnTest)); - assertNotNull(appInfo.lookupStaticTarget(methodXOnTestSuper, methodXOnTestSuper.holder)); + assertNotNull( + appInfo.lookupStaticTarget(methodXOnTestSuper.getReference(), methodXOnTestSuper)); // Accessing a private target on a different type will fail resolution outright. - assertNull(appInfo.lookupStaticTarget(methodXOnTest, methodXOnTest.holder)); + assertNull(appInfo.lookupStaticTarget(methodXOnTestReference, methodYOnTest)); assertEquals("OK", runArt(application)); } @@ -211,8 +213,7 @@ DexField aFieldOnInterface = factory .createField(factory.createType("LInterface;"), factory.intType, "aField"); - assertEquals(aFieldOnInterface, - appInfo.lookupStaticTarget(aFieldOnSubClass.holder, aFieldOnSubClass).field); + assertEquals(aFieldOnInterface, appInfo.lookupStaticTarget(aFieldOnSubClass).field); assertEquals("42", runArt(application)); @@ -244,13 +245,13 @@ DexType i3 = factory.createType("L" + pkg + "/I3;"); DexType i4 = factory.createType("L" + pkg + "/I4;"); DexType c0 = factory.createType("L" + pkg + "/C0;"); - DexType c1 = factory.createType("L" + pkg + "/C1;"); - DexType c2 = factory.createType("L" + pkg + "/C2;"); + DexProgramClass c1 = appInfo.definitionForProgramType(factory.createType("L" + pkg + "/C1;")); + DexProgramClass c2 = appInfo.definitionForProgramType(factory.createType("L" + pkg + "/C2;")); DexProto mProto = factory.createProto(factory.intType); DexString m = factory.createString("m"); DexMethod mOnC0 = factory.createMethod(c0, mProto, m); - DexMethod mOnC1 = factory.createMethod(c1, mProto, m); + DexMethod mOnC1 = factory.createMethod(c1.type, mProto, m); DexMethod mOnI0 = factory.createMethod(i0, mProto, m); DexMethod mOnI1 = factory.createMethod(i1, mProto, m); DexMethod mOnI2 = factory.createMethod(i2, mProto, m);
diff --git a/src/test/java/com/android/tools/r8/internal/NestTreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/NestTreeShakeJarVerificationTest.java index 2c06bd8..64b3fc0 100644 --- a/src/test/java/com/android/tools/r8/internal/NestTreeShakeJarVerificationTest.java +++ b/src/test/java/com/android/tools/r8/internal/NestTreeShakeJarVerificationTest.java
@@ -27,7 +27,7 @@ ImmutableList.of(BASE + DEPLOY_JAR)); assertEquals(0, filterKotlinMetadata(handler.warnings).count()); // TODO(b/155536535): We find bad descriptors. See if we can still resolve them. - assertEquals(2, filterKotlinMetadata(handler.infos).count()); + assertEquals(0, filterKotlinMetadata(handler.infos).count()); } private Stream<Diagnostic> filterKotlinMetadata(List<Diagnostic> warnings) {
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java index ccbfd3a..5048226 100644 --- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java +++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -72,10 +72,11 @@ private void testVirtualLookup(DexProgramClass clazz, DexEncodedMethod method) { // Check lookup will produce the same result. DexMethod id = method.method; - assertEquals(appInfo().resolveMethod(id.holder, method.method).getSingleTarget(), method); + assertEquals( + appInfo().resolveMethodOnClass(method.method, id.holder).getSingleTarget(), method); // Check lookup targets with include method. - ResolutionResult resolutionResult = appInfo().resolveMethodOnClass(clazz, method.method); + ResolutionResult resolutionResult = appInfo().resolveMethodOnClass(method.method, clazz); AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness. LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(
diff --git a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java index 2b3e44d..7104c9a 100644 --- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java +++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -8,7 +8,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import com.android.tools.r8.graph.AppInfoWithClassHierarchy; +import com.android.tools.r8.graph.AppInfo; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -61,8 +61,7 @@ InternalOptions options = new InternalOptions(); DexApplication application = buildApplication(builder, options); - AppView<AppInfoWithClassHierarchy> appView = - AppView.createForD8(new AppInfoWithClassHierarchy(application), options); + AppView<?> appView = AppView.createForD8(new AppInfo(application), options); // Return the processed method for inspection. MethodSubject methodSubject = getMethodSubject(application, signature); @@ -178,8 +177,7 @@ InternalOptions options = new InternalOptions(); DexApplication application = buildApplication(builder, options); - AppView<AppInfoWithClassHierarchy> appView = - AppView.createForD8(new AppInfoWithClassHierarchy(application), options); + AppView<?> appView = AppView.createForD8(new AppInfo(application), options); // Return the processed method for inspection. MethodSubject methodSubject = getMethodSubject(application, signature); @@ -303,8 +301,7 @@ InternalOptions options = new InternalOptions(); DexApplication application = buildApplication(builder, options); - AppView<AppInfoWithClassHierarchy> appView = - AppView.createForD8(new AppInfoWithClassHierarchy(application), options); + AppView<?> appView = AppView.createForD8(new AppInfo(application), options); // Return the processed method for inspection. MethodSubject methodSubject = getMethodSubject(application, signature); @@ -427,8 +424,7 @@ InternalOptions options = new InternalOptions(); DexApplication application = buildApplication(builder, options); - AppView<AppInfoWithClassHierarchy> appView = - AppView.createForD8(new AppInfoWithClassHierarchy(application), options); + AppView<?> appView = AppView.createForD8(new AppInfo(application), options); // Return the processed method for inspection. MethodSubject methodSubject = getMethodSubject(application, signature);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java b/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java index c337379..9362432 100644 --- a/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java +++ b/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.AnalysisTestBase; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Instruction; @@ -176,14 +177,14 @@ AppView<?> appView, EscapeAnalysis escapeAnalysis, Instruction escapeRoute, - DexMethod context) { + ProgramMethod context) { if (escapeRoute.isReturn() || escapeRoute.isThrow() || escapeRoute.isStaticPut()) { return false; } if (escapeRoute.isInvokeMethod()) { DexMethod invokedMethod = escapeRoute.asInvokeMethod().getInvokedMethod(); // Heuristic: if the call target has the same method name, it could be still local. - if (invokedMethod.name == context.name) { + if (invokedMethod.name == context.getReference().name) { return true; } // It's not legitimate during testing, except for recursion calls.
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java index 6177bf3..5a53fb5 100644 --- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java +++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -80,7 +80,7 @@ @Test public void testOptimizationInfo() throws Exception { - AppView<AppInfoWithClassHierarchy> appView = buildApp(); + AppView<? extends AppInfoWithClassHierarchy> appView = buildApp(); OptimizationFeedbackMock feedback = new OptimizationFeedbackMock(); FieldBitAccessAnalysis fieldBitAccessAnalysis = new FieldBitAccessAnalysis(); FieldAccessAnalysis fieldAccessAnalysis =
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java index 2590f1b..1bee09a 100644 --- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java +++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -11,6 +11,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.ir.code.Argument; @@ -45,7 +46,7 @@ boolean npeCaught, BiConsumer<AppView<?>, IRCode> inspector) throws Exception { - AppView<?> appView = build(mainClass); + AppView<? extends AppInfoWithClassHierarchy> appView = build(mainClass); CodeInspector codeInspector = new CodeInspector(appView.appInfo().app()); MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature); IRCode irCode = fooSubject.buildIR();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java index 50742b5..3d28b08 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -7,6 +7,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.InstancePut; @@ -32,7 +33,7 @@ int expectedNumberOfNonNull, Consumer<IRCode> testAugmentedIRCode) throws Exception { - AppView<?> appView = build(testClass); + AppView<? extends AppInfoWithClassHierarchy> appView = build(testClass); CodeInspector codeInspector = new CodeInspector(appView.appInfo().app()); MethodSubject fooSubject = codeInspector.clazz(testClass.getName()).method(signature); IRCode code = fooSubject.buildIR();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java index 28ab813..4820221 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
@@ -16,14 +16,15 @@ public abstract class NonNullTrackerTestBase extends TestBase { - protected AppView<?> build(Class<?> mainClass) throws Exception { + protected AppView<? extends AppInfoWithClassHierarchy> build(Class<?> mainClass) + throws Exception { Timing timing = Timing.empty(); AndroidApp app = buildAndroidApp(ToolHelper.getClassAsBytes(mainClass)); InternalOptions options = new InternalOptions(); DirectMappedDexApplication dexApplication = new ApplicationReader(app, options, timing).read().toDirect(); - AppView<?> appView = - AppView.createForD8(new AppInfoWithClassHierarchy(dexApplication), options); + AppView<? extends AppInfoWithClassHierarchy> appView = + AppView.createForR8(new AppInfoWithClassHierarchy(dexApplication), options); appView.setAppServices(AppServices.builder(appView).build()); return appView; }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java index 466b6fd..14d7e6b 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
@@ -31,16 +31,6 @@ } } - private void testD8(Class<?> testClass, List<MethodSignature> signatures) throws Exception { - CodeInspector codeInspector = - testForD8() - .addProgramClasses(testClass) - .addOptionsModification(options -> options.enableNonNullTracking = true) - .compile() - .inspector(); - verifyAbsenceOfIf(codeInspector, testClass, signatures); - } - private void testR8(Class<?> testClass, List<MethodSignature> signatures) throws Exception { CodeInspector codeInspector = testForR8(Backend.DEX) @@ -57,7 +47,6 @@ new MethodSignature("foo", "int", new String[]{"java.lang.String"}); MethodSignature bar = new MethodSignature("bar", "int", new String[]{"java.lang.String"}); - testD8(NonNullAfterInvoke.class, ImmutableList.of(foo, bar)); testR8(NonNullAfterInvoke.class, ImmutableList.of(foo, bar)); } @@ -67,7 +56,6 @@ new MethodSignature("foo", "int", new String[]{"java.lang.String[]"}); MethodSignature bar = new MethodSignature("bar", "int", new String[]{"java.lang.String[]"}); - testD8(NonNullAfterArrayAccess.class, ImmutableList.of(foo, bar)); testR8(NonNullAfterArrayAccess.class, ImmutableList.of(foo, bar)); } @@ -79,7 +67,6 @@ new String[]{FieldAccessTest.class.getCanonicalName()}); MethodSignature foo2 = new MethodSignature("foo2", "int", new String[]{FieldAccessTest.class.getCanonicalName()}); - testD8(NonNullAfterFieldAccess.class, ImmutableList.of(foo, bar, foo2)); testR8(NonNullAfterFieldAccess.class, ImmutableList.of(foo, bar, foo2)); } }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java new file mode 100644 index 0000000..cfdfcda --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java
@@ -0,0 +1,87 @@ +// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.ir.optimize.classinliner; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NeverMerge; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class ClassInliningWithImpreciseReceiverTypeTest extends TestBase { + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ClassInliningWithImpreciseReceiverTypeTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(ClassInliningWithImpreciseReceiverTypeTest.class) + .addKeepMainRule(TestClass.class) + .enableInliningAnnotations() + .enableMergeAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("C1", "C2"); + } + + static class TestClass { + + public static void main(String[] args) { + // After force inlining asB() and build(), the class inliner will attempt to force inline + // internalBuild(), but the receiver of that invoke is defined by a check-cast instruction + // that casts the receiver to B. + System.out.println(new C1().asB().build()); + System.out.println(new C2().asB().build()); + } + } + + @NeverMerge + abstract static class A { + + @NeverInline + B asB() { + return (B) this; + } + + @NeverInline + String build() { + return internalBuild(); + } + + abstract String internalBuild(); + } + + abstract static class B extends A {} + + static class C1 extends B { + + @NeverInline + String internalBuild() { + return System.currentTimeMillis() > 0 ? "C1" : null; + } + } + + static class C2 extends B { + + @NeverInline + String internalBuild() { + return System.currentTimeMillis() > 0 ? "C2" : null; + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java index f743bf2..c4dbbc4 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -106,31 +106,6 @@ } @Test - public void testD8() throws Exception { - assumeTrue("Only run D8 for Dex backend", parameters.isDexRuntime()); - - TestRunResult result = - testForD8() - .debug() - .addProgramClassesAndInnerClasses(MAIN) - .setMinApi(parameters.getRuntime()) - .addOptionsModification(options -> options.enableNonNullTracking = true) - .run(parameters.getRuntime(), MAIN) - .assertSuccessWithOutput(JAVA_OUTPUT); - test(result, false, false); - - result = - testForD8() - .release() - .addProgramClassesAndInnerClasses(MAIN) - .setMinApi(parameters.getRuntime()) - .addOptionsModification(options -> options.enableNonNullTracking = true) - .run(parameters.getRuntime(), MAIN) - .assertSuccessWithOutput(JAVA_OUTPUT); - test(result, false, true); - } - - @Test public void testR8() throws Exception { TestRunResult result = testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java new file mode 100644 index 0000000..bc0f2a4 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
@@ -0,0 +1,184 @@ +// Copyright (c) 2020, 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.kotlin.metadata; + +import static com.android.tools.r8.KotlinCompilerTool.KOTLINC; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNull; + +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.ToolHelper.KotlinTargetVersion; +import com.android.tools.r8.kotlin.KotlinMetadataWriter; +import com.android.tools.r8.shaking.ProguardKeepAttributes; +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.FoundClassSubject; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import kotlinx.metadata.jvm.KotlinClassHeader; +import kotlinx.metadata.jvm.KotlinClassMetadata; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class MetadataRewriteBoxedTypesTest extends KotlinMetadataTestBase { + + private final String EXPECTED = + StringUtils.lines("false", "0", "a", "0.042", "0.42", "42", "442", "1", "2", "42", "42"); + + @Parameterized.Parameters(name = "{0} target: {1}") + public static Collection<Object[]> data() { + return buildParameters( + getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values()); + } + + public MetadataRewriteBoxedTypesTest( + TestParameters parameters, KotlinTargetVersion targetVersion) { + super(targetVersion); + this.parameters = parameters; + } + + private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>(); + private final TestParameters parameters; + + @BeforeClass + public static void createLibJar() throws Exception { + String baseLibFolder = PKG_PREFIX + "/box_primitives_lib"; + for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) { + Path baseLibJar = + kotlinc(KOTLINC, targetVersion) + .addSourceFiles(getKotlinFileInTest(baseLibFolder, "lib")) + .compile(); + libJars.put(targetVersion, baseLibJar); + } + } + + @Test + public void smokeTest() throws Exception { + Path libJar = libJars.get(targetVersion); + Path output = + kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion) + .addClasspathFiles(libJar) + .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main")) + .setOutputPath(temp.newFolder().toPath()) + .compile(); + testForJvm() + .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar) + .addClasspath(output) + .run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt") + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void smokeTestReflection() throws Exception { + Path libJar = libJars.get(targetVersion); + Path output = + kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion) + .addClasspathFiles(libJar) + .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main_reflect")) + .setOutputPath(temp.newFolder().toPath()) + .compile(); + testForJvm() + .addVmArguments("-ea") + .addRunClasspathFiles( + ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar) + .addClasspath(output) + .run(parameters.getRuntime(), PKG + ".box_primitives_app.Main_reflectKt") + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testMetadataForLib() throws Exception { + Path libJar = + testForR8(parameters.getBackend()) + .addProgramFiles(libJars.get(targetVersion)) + .addKeepAllClassesRule() + .addKeepAttributes( + ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS, + ProguardKeepAttributes.SIGNATURE, + ProguardKeepAttributes.INNER_CLASSES, + ProguardKeepAttributes.ENCLOSING_METHOD) + .compile() + .inspect(this::inspect) + .writeToZip(); + Path main = + kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion) + .addClasspathFiles(libJar) + .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main")) + .setOutputPath(temp.newFolder().toPath()) + .compile(); + testForJvm() + .addRunClasspathFiles( + ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar) + .addClasspath(main) + .run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt") + .assertSuccessWithOutput(EXPECTED); + } + + private void inspect(CodeInspector inspector) throws IOException, ExecutionException { + // Since this has a keep-all classes rule, we should just assert that the meta-data is equal to + // the original one. + CodeInspector stdLibInspector = new CodeInspector(libJars.get(targetVersion)); + for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) { + ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName()); + assertThat(r8Clazz, isPresent()); + KotlinClassMetadata originalMetadata = clazzSubject.getKotlinClassMetadata(); + KotlinClassMetadata rewrittenMetadata = r8Clazz.getKotlinClassMetadata(); + if (originalMetadata == null) { + assertNull(rewrittenMetadata); + continue; + } + assertNotNull(rewrittenMetadata); + KotlinClassHeader originalHeader = originalMetadata.getHeader(); + KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader(); + assertEquals(originalHeader.getKind(), rewrittenHeader.getKind()); + assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName()); + // We cannot assert equality of the data since it may be ordered differently. Instead we use + // the KotlinMetadataWriter. + String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata); + String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata); + assertEquals(expected, actual); + } + } + + @Test + public void testMetadataForReflect() throws Exception { + Path libJar = + testForR8(parameters.getBackend()) + .addProgramFiles(libJars.get(targetVersion)) + .addKeepAllClassesRule() + .addKeepAttributes( + ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS, + ProguardKeepAttributes.SIGNATURE, + ProguardKeepAttributes.INNER_CLASSES, + ProguardKeepAttributes.ENCLOSING_METHOD) + .compile() + .writeToZip(); + Path main = + kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion) + .addClasspathFiles(libJar) + .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main_reflect")) + .setOutputPath(temp.newFolder().toPath()) + .compile(); + testForJvm() + .addVmArguments("-ea") + .addRunClasspathFiles( + ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar) + .addClasspath(main) + .run(parameters.getRuntime(), PKG + ".box_primitives_app.Main_reflectKt") + .assertSuccessWithOutput(EXPECTED); + } +}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_app/main.kt new file mode 100644 index 0000000..2a7cb0c --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_app/main.kt
@@ -0,0 +1,31 @@ +// Copyright (c) 2020, 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.kotlin.metadata.box_primitives_app + +import com.android.tools.r8.kotlin.metadata.box_primitives_lib.Test + +fun main() { + var test = Test() + test.testBoolean.add(test.boolean) + println(test.getFirstBoolean(test.testBoolean)) + test.testByte.add(test.byte) + println(test.getFirstByte(test.testByte)) + test.testChar.add(test.char) + println(test.getFirstChar(test.testChar)) + test.testDouble.add(test.double) + println(test.getFirstDouble(test.testDouble)) + test.testFloat.add(test.float) + println(test.getFirstFloat(test.testFloat)) + test.testInt.add(test.int) + println(test.getFirstInt(test.testInt)) + test.testLong.add(test.long) + println(test.getFirstLong(test.testLong)) + test.testShort.add(test.short) + println(test.getFirstShort(test.testShort)) + test.testNumber.add(test.number) + println(test.getFirstNumber(test.testNumber)) + test.functionWithUnit { println(it) } + test.functionWithVoid { println(it); null } +} \ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_app/main_reflect.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_app/main_reflect.kt new file mode 100644 index 0000000..be89c90 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_app/main_reflect.kt
@@ -0,0 +1,72 @@ +// Copyright (c) 2020, 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.kotlin.metadata.box_primitives_app + +import com.android.tools.r8.kotlin.metadata.box_primitives_lib.Test + +fun trivialTypeAssertionsForProperties() { + val test = Test() + assert(test::boolean.returnType.classifier.toString().equals("class kotlin.Boolean")) + assert(test::byte.returnType.classifier.toString().equals("class kotlin.Byte")) + assert(test::char.returnType.classifier.toString().equals("class kotlin.Char")) + assert(test::double.returnType.classifier.toString().equals("class kotlin.Double")) + assert(test::float.returnType.classifier.toString().equals("class kotlin.Float")) + assert(test::int.returnType.classifier.toString().equals("class kotlin.Int")) + assert(test::long.returnType.classifier.toString().equals("class kotlin.Long")) + assert(test::short.returnType.classifier.toString().equals("class kotlin.Short")) + assert(test::number.returnType.classifier.toString().equals("class kotlin.Number")) +} + +fun trivialTypeAssertionsForFunctions() { + val test = Test() + assert(test::getFirstBoolean.parameters.size == 1) + assert(test::getFirstBoolean.parameters.get(0).name == "l") + assert(test::getFirstBoolean + .parameters.get(0).type.classifier.toString() == "class kotlin.collections.List") + assert(test::getFirstBoolean.parameters.get(0).type.arguments.size == 1) + assert(test::getFirstBoolean + .parameters.get(0).type.arguments.get(0).type!!.classifier.toString().equals( + test::boolean.returnType.classifier.toString())) +} + +fun runReflective() { + val test = Test() + // Test boxed types + test::boolean.set(false) + test::testBoolean.get().add(test::boolean.get()) + println(test::getFirstBoolean.call(test::testBoolean.get())) + test::byte.set(0) + test::testByte.get().add(test::byte.get()) + println(test::getFirstByte.call(test::testByte.get())) + test::char.set('a') + test::testChar.get().add(test::char.get()) + println(test::getFirstChar.call(test::testChar.get())) + test::double.set(0.042) + test::testDouble.get().add(test::double.get()) + println(test::getFirstDouble.call(test::testDouble.get())) + test::float.set(0.42F) + test::testFloat.get().add(test::float.get()) + println(test::getFirstFloat.call(test::testFloat.get())) + test::int.set(42) + test::testInt.get().add(test::int.get()) + println(test::getFirstInt.call(test::testInt.get())) + test::long.set(442) + test::testLong.get().add(test::long.get()) + println(test::getFirstLong.call(test::testLong.get())) + test::short.set(1) + test::testShort.get().add(test::short.get()) + println(test::getFirstShort.call(test::testShort.get())) + test::number.set(2) + test::testNumber.get().add(test::number.get()) + println(test::getFirstNumber.call(test::testNumber.get())) + test::functionWithUnit.call({ i: Int -> println(i) }) + test::functionWithVoid.call({ i: Int -> println(i); null }) +} + +fun main() { + trivialTypeAssertionsForProperties() + trivialTypeAssertionsForFunctions() + runReflective() +} \ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_lib/lib.kt new file mode 100644 index 0000000..7193b62 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/box_primitives_lib/lib.kt
@@ -0,0 +1,41 @@ +// Copyright (c) 2020, 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.kotlin.metadata.box_primitives_lib + +class Test { + + val testReadOnly : List<Boolean> = listOf() + + var boolean : Boolean = false + var testBoolean : MutableList<Boolean> = mutableListOf() + var byte : Byte = 0 + var testByte : MutableList<Byte> = mutableListOf() + var char : Char = 'a' + var testChar : MutableList<Char> = mutableListOf() + var double : Double = 0.042 + var testDouble : MutableList<Double> = mutableListOf() + var float : Float = 0.42F + var testFloat : MutableList<Float> = mutableListOf() + var int : Int = 42 + var testInt : MutableList<Int> = mutableListOf() + var long : Long = 442 + var testLong : MutableList<Long> = mutableListOf() + var short : Short = 1 + var testShort : MutableList<Short> = mutableListOf() + var number : Number = 2 + var testNumber : MutableList<Number> = mutableListOf() + + fun getFirstBoolean(l : List<Boolean>) : Boolean = l.get(0) + fun getFirstByte(l : List<Byte>) : Byte = l.get(0) + fun getFirstChar(l : List<Char>) : Char = l.get(0) + fun getFirstDouble(l : List<Double>) : Double = l.get(0) + fun getFirstFloat(l : List<Float>) : Float = l.get(0) + fun getFirstInt(l : List<Int>) : Int = l.get(0) + fun getFirstLong(l : List<Long>) : Long = l.get(0) + fun getFirstShort(l : List<Short>) : Short = l.get(0) + fun getFirstNumber(l : List<Number>) : Number = l.get(0) + fun functionWithUnit(consumer : (Int) -> Unit) = consumer(42) + fun functionWithVoid(consumer : (Int) -> Void?) = consumer(42) +}
diff --git a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java index 02cb64e..4ad2bed 100644 --- a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java +++ b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
@@ -51,20 +51,18 @@ }; DexEncodedMethod langObjectNotifyMethod = appInfo - .resolveMethod( - fooType, + .resolveMethodOnClass( factory.createMethod(fooType, factory.createProto(factory.voidType), "notify")) .getSingleTarget(); for (DexType arrType : arrayTypes) { assertNull( appInfo - .resolveMethod( - arrType, factory.createMethod(arrType, factory.createProto(arrType), "clone")) + .resolveMethodOnClass( + factory.createMethod(arrType, factory.createProto(arrType), "clone")) .getSingleTarget()); DexEncodedMethod target = appInfo - .resolveMethod( - arrType, + .resolveMethodOnClass( factory.createMethod(arrType, factory.createProto(factory.voidType), "notify")) .getSingleTarget(); assertEquals(langObjectNotifyMethod, target);
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java index bade483..8f4ec7b 100644 --- a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java +++ b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
@@ -58,7 +58,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(Base.class, "collect", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); assertTrue(resolutionResult.isSingleResolution()); DexProgramClass context = appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java index 7bd9cc9..c119db0 100644 --- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java +++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.LookupResult; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.resolution.singletarget.Main; import com.android.tools.r8.resolution.singletarget.one.AbstractSubClass; @@ -32,9 +33,8 @@ import com.android.tools.r8.resolution.singletarget.two.OtherSubSubClassTwo; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.google.common.collect.ImmutableList; -import java.io.IOException; +import com.google.common.collect.Sets; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.Assert; @@ -76,9 +76,9 @@ public SingleTargetLookupTest( String methodName, - Class invokeReceiver, - Class singleTargetHolderOrNull, - List<Class> virtualTargetHolders) { + Class<?> invokeReceiver, + Class<?> singleTargetHolderOrNull, + List<Class<?>> virtualTargetHolders) { this.methodName = methodName; this.invokeReceiver = invokeReceiver; this.singleTargetHolderOrNull = singleTargetHolderOrNull; @@ -166,22 +166,24 @@ }); } - private static DexType toType(Class clazz, AppInfo appInfo) { + private static DexType toType(Class<?> clazz, AppInfo appInfo) { return buildType(clazz, appInfo.dexItemFactory()); } private final String methodName; - private final Class invokeReceiver; - private final Class singleTargetHolderOrNull; - private final List<Class> virtualTargetHolders; + private final Class<?> invokeReceiver; + private final Class<?> singleTargetHolderOrNull; + private final List<Class<?>> virtualTargetHolders; @Test public void lookupSingleTarget() { - DexMethod method = buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory()); - Assert.assertNotNull( - appInfo.resolveMethod(toType(invokeReceiver, appInfo), method).getSingleTarget()); + DexMethod reference = + buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory()); + ProgramMethod context = + appInfo.definitionForProgramType(reference.holder).getProgramDefaultInitializer(); + Assert.assertNotNull(appInfo.resolveMethodOnClass(reference).getSingleTarget()); DexEncodedMethod singleVirtualTarget = - appInfo.lookupSingleVirtualTarget(method, method.holder, false); + appInfo.lookupSingleVirtualTarget(reference, context, false); if (singleTargetHolderOrNull == null) { Assert.assertNull(singleVirtualTarget); } else { @@ -191,11 +193,10 @@ } @Test - public void lookupVirtualTargets() throws IOException { + public void lookupVirtualTargets() { DexMethod method = buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory()); - Assert.assertNotNull( - appInfo.resolveMethod(toType(invokeReceiver, appInfo), method).getSingleTarget()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + Assert.assertNotNull(appInfo.resolveMethodOnClass(method).getSingleTarget()); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); if (resolutionResult.isVirtualTarget()) { LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets( @@ -203,7 +204,7 @@ appInfo); assertTrue(lookupResult.isLookupResultSuccess()); assertFalse(lookupResult.asLookupResultSuccess().hasLambdaTargets()); - Set<DexType> targetHolders = new HashSet<>(); + Set<DexType> targetHolders = Sets.newIdentityHashSet(); lookupResult .asLookupResultSuccess() .forEach(
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java index 28b468e..c0996fe 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -80,7 +80,7 @@ @Test public void resolveTarget() { - ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); assertTrue(resolutionResult instanceof IllegalAccessOrNoSuchMethodResult); }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java index 1da4ff7..5da5b2d 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
@@ -101,7 +101,7 @@ @Test public void testResolution() { - ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); assertTrue(resolutionResult.isFailedResolution()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java index eb40786..5b08461 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
@@ -14,6 +14,8 @@ import com.android.tools.r8.TestRunResult; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.AndroidApiLevel; @@ -108,9 +110,9 @@ } private final TestParameters parameters; - private final DexMethod methodOnA = buildMethod(A.class, "f"); - private final DexMethod methodOnB = buildMethod(B.class, "f"); - private final DexMethod methodOnC = buildMethod(C.class, "f"); + private final DexMethod methodOnAReference = buildMethod(A.class, "f"); + private final DexMethod methodOnBReference = buildMethod(B.class, "f"); + private final DexMethod methodOnCReference = buildMethod(C.class, "f"); public VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest(TestParameters parameters) { this.parameters = parameters; @@ -118,21 +120,24 @@ @Test public void lookupSingleTarget() { + DexProgramClass bClass = appInfo.definitionForProgramType(methodOnBReference.holder); + ProgramMethod methodOnB = bClass.lookupProgramMethod(methodOnBReference); ResolutionResult resolutionResult = - appInfo.resolveMethodOnInterface(methodOnB.holder, methodOnB); + appInfo.resolveMethodOnInterface(methodOnBReference.holder, methodOnBReference); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); - assertEquals(methodOnB, resolved.method); + assertEquals(methodOnBReference, resolved.method); assertFalse(resolutionResult.isVirtualTarget()); DexEncodedMethod singleVirtualTarget = - appInfo.lookupSingleVirtualTarget(methodOnB, methodOnB.holder, false); + appInfo.lookupSingleVirtualTarget(methodOnBReference, methodOnB, false); Assert.assertNull(singleVirtualTarget); } @Test public void lookupVirtualTargets() { - ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(methodOnB.holder, methodOnB); + ResolutionResult resolutionResult = + appInfo.resolveMethodOnInterface(methodOnBReference.holder, methodOnBReference); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); - assertEquals(methodOnB, resolved.method); + assertEquals(methodOnBReference, resolved.method); assertFalse(resolutionResult.isVirtualTarget()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java index 1f24983..fe66478 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -16,6 +16,7 @@ import com.android.tools.r8.ToolHelper.DexVm; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.google.common.collect.ImmutableList; @@ -165,18 +166,19 @@ @Test public void lookupSingleTarget() { - ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB); + DexProgramClass bClass = appInfo.definitionForProgramType(methodOnB.holder); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); assertEquals(methodOnA, resolved.method); assertFalse(resolutionResult.isVirtualTarget()); DexEncodedMethod singleVirtualTarget = - appInfo.lookupSingleVirtualTarget(methodOnB, methodOnB.holder, false); + appInfo.lookupSingleVirtualTarget(methodOnB, bClass.getProgramDefaultInitializer(), false); Assert.assertNull(singleVirtualTarget); } @Test public void lookupVirtualTargets() { - ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); assertEquals(methodOnA, resolved.method); assertFalse(resolutionResult.isVirtualTarget());
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java index 67bf3e3..65e2ed5 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -120,7 +120,7 @@ // Resolve the method from the point of the declared holder. assertEquals(method.holder, declaredClassDefinition.type); - ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(declaredClassDefinition, method); if (!symbolicReferenceIsDefiningType) { // The targeted method is a private interface method and thus not a maximally specific method.
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java index a25f3c6..364014c 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
@@ -120,7 +120,7 @@ // Resolve the method from the point of the declared holder. assertEquals(method.holder, declaredClassDefinition.type); - ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(declaredClassDefinition, method); // The targeted method is a private interface method and thus not a maximally specific method. assertTrue(resolutionResult instanceof NoSuchMethodResult);
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java index 026055c..25a5d9e 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -95,7 +95,7 @@ // Resolve the method from the point of the declared holder. assertEquals(method.holder, declaredClassDefinition.type); - ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(declaredClassDefinition, method); // Verify that the resolved method is on the defining class. assertEquals(
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java index f1e182a..4453f58 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -121,7 +121,7 @@ // Resolve the method from the point of the declared holder. assertEquals(method.holder, declaredClassDefinition.type); - ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(declaredClassDefinition, method); // Resolution fails when there is a mismatch between the symbolic reference and the definition. if (!symbolicReferenceIsDefiningType) {
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java index 4f013bb..aced457 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
@@ -97,7 +97,7 @@ // Resolve the method from the point of the declared holder. assertEquals(method.holder, declaredClassDefinition.type); - ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(declaredClassDefinition, method); // Verify that the resolved method is on the defining class. assertEquals(
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java index 15f7edc..2000456 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
@@ -70,7 +70,7 @@ DexProgramClass bClass = appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass(); DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(bar.holder, bar); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar); assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java index 4041e47..0460ce5 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
@@ -72,7 +72,7 @@ DexProgramClass bClass = appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass(); DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(bar.holder, bar); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar); assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java index 8dc4191..5e2743c 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
@@ -72,7 +72,7 @@ DexProgramClass bClass = appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass(); DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(bar.holder, bar); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar); assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java index d6e6ab9..4aff595 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -71,7 +71,7 @@ DexProgramClass bClass = appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass(); DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(bar.holder, bar); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar); assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java index 020ec02..f2d4c5c 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
@@ -56,7 +56,7 @@ DexProgramClass aClass = appInfo.definitionFor(buildType(A.class, appInfo.dexItemFactory())).asProgramClass(); DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(bar.holder, bar); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar); assertEquals(OptionalBool.TRUE, resolutionResult.isAccessibleFrom(aClass, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java index 4616af8..4d0f445 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
@@ -4,17 +4,17 @@ package com.android.tools.r8.resolution.access.indirectfield; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.TestRunResult; -import com.android.tools.r8.graph.AccessControl; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexClass; -import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.FieldResolutionResult; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.references.Reference; import com.android.tools.r8.resolution.access.indirectfield.pkg.C; import com.android.tools.r8.shaking.AppInfoWithLiveness; @@ -53,18 +53,17 @@ AppInfoWithLiveness appInfo = appView.appInfo(); DexProgramClass cClass = appInfo.definitionFor(buildType(C.class, appInfo.dexItemFactory())).asProgramClass(); + ProgramMethod barMethod = + cClass.lookupProgramMethod( + buildMethod(C.class.getDeclaredMethod("bar"), appInfo.dexItemFactory())); DexField f = buildField( // Reflecting on B.class.getField("f") will give A.f, so manually create the reference. Reference.field(Reference.classFromClass(B.class), "f", Reference.INT), appInfo.dexItemFactory()); - DexClass initialResolutionHolder = appInfo.definitionFor(f.holder); - DexEncodedField resolutionTarget = appInfo.resolveField(f); - // TODO(b/145723539): Test access via the resolution result once possible. - assertEquals( - OptionalBool.TRUE, - AccessControl.isFieldAccessible( - resolutionTarget, initialResolutionHolder, cClass, appInfo)); + FieldResolutionResult resolutionResult = appInfo.resolveField(f); + assertTrue(resolutionResult.isSuccessfulResolution()); + assertEquals(OptionalBool.TRUE, resolutionResult.isAccessibleFrom(barMethod, appInfo)); } @Test
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java index bdd8484..6e51158 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
@@ -61,7 +61,7 @@ DexProgramClass cClass = appInfo.definitionFor(buildType(C.class, appInfo.dexItemFactory())).asProgramClass(); DexMethod bar = buildMethod(B.class.getMethod("foo"), appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(bar.holder, bar); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar); assertEquals( OptionalBool.TRUE, resolutionResult.isAccessibleForVirtualDispatchFrom(cClass, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java index b6023ce..b031eca 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
@@ -44,7 +44,7 @@ AndroidApp app = readClasses(CLASSES); AppInfoWithLiveness appInfo = computeAppViewWithLiveness(app, Main.class).appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); // Currently R8 will resolve to L::f as that is the first in the topological search. // Resolution may return any of the matches, so it is valid if this expectation changes.
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java index 2068ef1..429b8d9 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
@@ -49,7 +49,7 @@ Main.class) .appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); assertEquals(L.class.getTypeName(), resolutionTarget.holder().toSourceString()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java index 64908c4..a1e3185 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
@@ -49,7 +49,7 @@ Main.class) .appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); assertEquals(R.class.getTypeName(), resolutionTarget.holder().toSourceString()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java index 4841f77..44c41eb 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
@@ -52,7 +52,7 @@ Main.class) .appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); assertEquals(L.class.getTypeName(), resolutionTarget.holder().toSourceString()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java index 6059ea1..7683037 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
@@ -52,7 +52,7 @@ Main.class) .appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); assertEquals(R.class.getTypeName(), resolutionTarget.holder().toSourceString()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java index 433575f..6fa3216 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
@@ -51,7 +51,7 @@ Main.class) .appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); Set<String> holders = new HashSet<>(); resolutionResult .asFailedResolution()
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java index e04908b..ccac0ed 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
@@ -43,7 +43,7 @@ AppInfoWithLiveness appInfo = computeAppViewWithLiveness(readClasses(CLASSES), Main.class).appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); assertEquals(L.class.getTypeName(), resolutionTarget.holder().toSourceString()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java index 7472e89..54a9b59 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
@@ -43,7 +43,7 @@ AppInfoWithLiveness appInfo = computeAppViewWithLiveness(readClasses(CLASSES), Main.class).appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); assertEquals(R.class.getTypeName(), resolutionTarget.holder().toSourceString()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java index 5966b9d..a311b5a 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
@@ -52,7 +52,7 @@ Main.class) .appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); Set<String> holders = new HashSet<>(); resolutionResult .asFailedResolution()
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java index e59009e..8d2a599 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
@@ -59,7 +59,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo); @@ -102,7 +102,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java index cb44081..ef5656d 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
@@ -57,7 +57,7 @@ buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java index 9a17065..e29f3fc 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
@@ -65,7 +65,7 @@ AssertionError.class, () -> appInfo - .resolveMethod(method.holder, method) + .resolveMethodOnInterface(method) .lookupVirtualDispatchTargets(context, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java index 81ed494..b4009fb 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
@@ -56,7 +56,7 @@ AssertionError.class, () -> appInfo - .resolveMethod(method.holder, method) + .resolveMethodOnInterface(method) .lookupVirtualDispatchTargets(context, appInfo)); }
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java index f0b55f2..1033136 100644 --- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java +++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
@@ -68,7 +68,7 @@ buildClasses(C.class, Main.class).addClasspathFiles(classPathJar).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(Abstract.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Abstract.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java index 01d5afb..3a20a43 100644 --- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java +++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
@@ -56,7 +56,7 @@ buildClasses(A.class, B.class, C.class, D.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java index 37d915a..81920cb 100644 --- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java +++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
@@ -60,7 +60,7 @@ buildClasses(A.class, B.class, C.class, D.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java index e8c34d1..a964f73 100644 --- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java +++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
@@ -72,7 +72,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java index 338d00a..ed64145 100644 --- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java +++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
@@ -71,7 +71,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java index e7d36e9..d86de60 100644 --- a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java +++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
@@ -57,7 +57,7 @@ buildClasses(A.class, B.class, C.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java index c15c379..abd4956 100644 --- a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java +++ b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.LookupResult; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.Nullability; @@ -52,11 +53,15 @@ DexType typeA = buildType(A.class, appInfo.dexItemFactory()); DexType typeB = buildType(B.class, appInfo.dexItemFactory()); DexType typeMain = buildType(Main.class, appInfo.dexItemFactory()); + DexMethod mainMethodReference = + buildMethod(Main.class.getDeclaredMethod("main", String[].class), appInfo.dexItemFactory()); + ProgramMethod mainMethod = + appInfo.definitionForProgramType(typeMain).lookupProgramMethod(mainMethodReference); DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); ClassTypeElement latticeB = ClassTypeElement.create(typeB, Nullability.definitelyNotNull(), appView); DexEncodedMethod singleTarget = - appInfo.lookupSingleVirtualTarget(fooA, typeMain, false, t -> false, typeA, latticeB); + appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, latticeB); assertNotNull(singleTarget); DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory()); assertEquals(fooB, singleTarget.method); @@ -72,11 +77,15 @@ DexType typeA = buildType(A.class, appInfo.dexItemFactory()); DexType typeB = buildType(B.class, appInfo.dexItemFactory()); DexType typeMain = buildType(Main.class, appInfo.dexItemFactory()); + DexMethod mainMethodReference = + buildMethod(Main.class.getDeclaredMethod("main", String[].class), appInfo.dexItemFactory()); + ProgramMethod mainMethod = + appInfo.definitionForProgramType(typeMain).lookupProgramMethod(mainMethodReference); DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); ClassTypeElement latticeB = ClassTypeElement.create(typeB, Nullability.definitelyNotNull(), appView); DexEncodedMethod singleTarget = - appInfo.lookupSingleVirtualTarget(fooA, typeMain, false, t -> false, typeA, latticeB); + appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, latticeB); assertNotNull(singleTarget); DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory()); assertEquals(fooB, singleTarget.method); @@ -94,10 +103,14 @@ DexType typeA = buildType(A.class, appInfo.dexItemFactory()); DexType typeC = buildType(C.class, appInfo.dexItemFactory()); DexType typeMain = buildType(MainAllInstantiated.class, appInfo.dexItemFactory()); + DexMethod mainMethodReference = + buildMethod(Main.class.getDeclaredMethod("main", String[].class), appInfo.dexItemFactory()); + ProgramMethod mainMethod = + appInfo.definitionForProgramType(typeMain).lookupProgramMethod(mainMethodReference); DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory()); DexMethod fooC = buildNullaryVoidMethod(C.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolution = appInfo.resolveMethod(typeA, fooA); + ResolutionResult resolution = appInfo.resolveMethodOnClass(fooA); DexProgramClass context = appView.definitionForProgramType(typeMain); DexProgramClass upperBound = appView.definitionForProgramType(typeA); DexProgramClass lowerBound = appView.definitionForProgramType(typeC); @@ -120,7 +133,7 @@ ClassTypeElement latticeC = ClassTypeElement.create(typeC, Nullability.definitelyNotNull(), appView); DexEncodedMethod singleTarget = - appInfo.lookupSingleVirtualTarget(fooA, typeMain, false, t -> false, typeA, latticeC); + appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, latticeC); assertNull(singleTarget); }
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java index 870c9cc..9489060 100644 --- a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java +++ b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
@@ -15,6 +15,7 @@ import com.android.tools.r8.graph.DexEncodedMethod; 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.shaking.AppInfoWithLiveness; import java.util.ArrayList; import org.junit.Test; @@ -42,14 +43,18 @@ factory -> new ArrayList<>(buildKeepRuleForClassAndMethods(Main.class, factory))); AppInfoWithLiveness appInfo = appView.appInfo(); DexType typeMain = buildType(Main.class, appInfo.dexItemFactory()); + DexMethod mainMethodReference = + buildMethod(Main.class.getDeclaredMethod("main", String[].class), appInfo.dexItemFactory()); + ProgramMethod mainMethod = + appInfo.definitionForProgramType(typeMain).lookupProgramMethod(mainMethodReference); DexType typeA = buildType(A.class, appInfo.dexItemFactory()); DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); DexEncodedMethod singleTarget = - appInfo.lookupSingleVirtualTarget(fooA, typeMain, false, t -> false, typeA, null); + appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, null); assertNotNull(singleTarget); assertEquals(fooA, singleTarget.method); DexEncodedMethod invalidSingleTarget = - appInfo.lookupSingleVirtualTarget(fooA, typeMain, true, t -> false, typeA, null); + appInfo.lookupSingleVirtualTarget(fooA, mainMethod, true, t -> false, typeA, null); assertNull(invalidSingleTarget); } @@ -61,15 +66,19 @@ factory -> new ArrayList<>(buildKeepRuleForClassAndMethods(Main.class, factory))); AppInfoWithLiveness appInfo = appView.appInfo(); DexType typeMain = buildType(Main.class, appInfo.dexItemFactory()); + DexMethod mainMethodReference = + buildMethod(Main.class.getDeclaredMethod("main", String[].class), appInfo.dexItemFactory()); + ProgramMethod mainMethod = + appInfo.definitionForProgramType(typeMain).lookupProgramMethod(mainMethodReference); DexType typeA = buildType(I.class, appInfo.dexItemFactory()); DexMethod fooI = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory()); DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); DexEncodedMethod singleTarget = - appInfo.lookupSingleVirtualTarget(fooI, typeMain, true, t -> false, typeA, null); + appInfo.lookupSingleVirtualTarget(fooI, mainMethod, true, t -> false, typeA, null); assertNotNull(singleTarget); assertEquals(fooA, singleTarget.method); DexEncodedMethod invalidSingleTarget = - appInfo.lookupSingleVirtualTarget(fooI, typeMain, false, t -> false, typeA, null); + appInfo.lookupSingleVirtualTarget(fooI, mainMethod, false, t -> false, typeA, null); assertNull(invalidSingleTarget); }
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java index 750c642..7f52044 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
@@ -56,7 +56,7 @@ buildClasses(A.class, B.class, C.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java index 8bc102b..6264f35 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
@@ -56,7 +56,7 @@ buildClasses(I.class, J.class, A.class, B.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java index 469c0ad..8f818b2 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
@@ -56,7 +56,7 @@ buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java index f025e17..2b236b5 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
@@ -59,7 +59,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java index d8f8c4a..b75b7ac 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
@@ -58,7 +58,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); assertTrue(resolutionResult.isSingleResolution()); DexType mainType = buildType(Main.class, appInfo.dexItemFactory()); DexProgramClass main = appView.definitionForProgramType(mainType);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java index 472f7a1..9c7245c 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
@@ -55,7 +55,7 @@ computeAppViewWithLiveness(buildClasses(A.class, I.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java index d3c1b7a..745ff4b 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -86,7 +86,7 @@ }); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(initial, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Unrelated.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo); @@ -233,7 +233,7 @@ .build()); AppInfoWithClassHierarchy appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexType typeA = buildType(A.class, appInfo.dexItemFactory()); DexType typeB = buildType(B.class, appInfo.dexItemFactory()); DexProgramClass classB = appInfo.definitionForProgramType(typeB); @@ -266,7 +266,7 @@ computeAppViewWithLiveness(buildClasses(Unrelated.class).build(), Unrelated.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(Unrelated.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Unrelated.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java index 477bed8..c74b196 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
@@ -61,7 +61,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(Top.class, "clear", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(TopRunner.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java index b9f8c90..e5904db 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
@@ -68,7 +68,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType( buildType(ViewModelRunner.class, appInfo.dexItemFactory())); @@ -116,7 +116,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo); @@ -162,7 +162,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType( buildType(ViewModelRunnerWithCast.class, appInfo.dexItemFactory()));
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java index c4fb6d2..e7319cd 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
@@ -60,7 +60,7 @@ Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method); DexProgramClass context = appView.definitionForProgramType(buildType(B.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java index b6f838b..fbf8ac5 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
@@ -57,7 +57,7 @@ buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class); AppInfoWithLiveness appInfo = appView.appInfo(); DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory()); - ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method); + ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method); DexProgramClass context = appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory())); LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);