Merge commit '072f610d7f11a5d9f6614e5d1c9e847383db5efe' into dev-release
diff --git a/.gitignore b/.gitignore index aa4c9ae..b382c4f 100644 --- a/.gitignore +++ b/.gitignore
@@ -3,7 +3,6 @@ !third_party/gmscore/*.sha1 !third_party/internal/*.sha1 !third_party/nest/*.sha1 -!third_party/photos/*.sha1 !third_party/proguard/*.sha1 !third_party/youtube/*sha1 #*# @@ -125,7 +124,6 @@ third_party/openjdk/openjdk-rt-1.8.tar.gz third_party/opensource_apps third_party/opensource_apps.tar.gz -third_party/photos/* third_party/proguard/* third_party/proguardsettings.tar.gz third_party/proguardsettings/
diff --git a/build.gradle b/build.gradle index 2e2132d..730d291 100644 --- a/build.gradle +++ b/build.gradle
@@ -425,7 +425,6 @@ "gmscore/v7", "gmscore/v8", "nest/nest_20180926_7c6cfb", - "photos/2017-06-06", "proguard/proguard_internal_159423826", "proguardsettings", "proto",
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java index 99ff6a7..3651899 100644 --- a/src/main/java/com/android/tools/r8/D8.java +++ b/src/main/java/com/android/tools/r8/D8.java
@@ -165,8 +165,9 @@ throws IOException { PrefixRewritingMapper rewritePrefix = options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options); - LazyLoadedDexApplication app = new ApplicationReader(inputApp, options, timing).read(executor); - AppInfo appInfo = AppInfo.createInitialAppInfo(app); + ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing); + LazyLoadedDexApplication app = applicationReader.read(executor); + AppInfo appInfo = AppInfo.createInitialAppInfo(app, applicationReader.readMainDexClasses(app)); return AppView.createForD8(appInfo, rewritePrefix); } @@ -280,13 +281,15 @@ DexApplication app = rewriteNonDexInputs( appView, inputApp, options, executor, timing, appView.appInfo().app()); - appView.setAppInfo(new AppInfo(app, appView.appInfo().getSyntheticItems().commit(app))); + appView.setAppInfo( + new AppInfo( + app, + appView.appInfo().getMainDexClasses(), + appView.appInfo().getSyntheticItems().commit(app))); namingLens = NamingLens.getIdentityLens(); } new ApplicationWriter( - appView.appInfo().app(), appView, - options, marker == null ? null : ImmutableList.copyOf(markers), GraphLens.getIdentityLens(), InitClassLens.getDefault(), @@ -307,7 +310,7 @@ } private static DexApplication rewriteNonDexInputs( - AppView<?> appView, + AppView<AppInfo> appView, AndroidApp inputApp, InternalOptions options, ExecutorService executor, @@ -333,6 +336,11 @@ } } DexApplication cfApp = app.builder().replaceProgramClasses(nonDexProgramClasses).build(); + appView.setAppInfo( + new AppInfo( + cfApp, + appView.appInfo().getMainDexClasses(), + appView.appInfo().getSyntheticItems().commit(cfApp))); ConvertedCfFiles convertedCfFiles = new ConvertedCfFiles(); NamingLens prefixRewritingNamingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView); @@ -340,9 +348,7 @@ .run(appView.appInfo().classes(), executor); new KotlinMetadataRewriter(appView, prefixRewritingNamingLens).runForD8(executor); new ApplicationWriter( - cfApp, appView, - options, null, GraphLens.getIdentityLens(), InitClassLens.getDefault(),
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java index 49ab77b..4d1c0dc 100644 --- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java +++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -85,13 +85,17 @@ try { try { Timing timing = new Timing("DexFileMerger"); + ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing); DexApplication app = - new ApplicationReader(inputApp, options, timing) - .read( - null, - executor, - new DexFileMergerHelper(inputOrdering)::keepFirstProgramClassConflictResolver); - AppView<AppInfo> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app)); + applicationReader.read( + null, + executor, + new DexFileMergerHelper(inputOrdering)::keepFirstProgramClassConflictResolver); + + AppView<AppInfo> appView = + AppView.createForD8( + AppInfo.createInitialAppInfo(app, applicationReader.readMainDexClasses(app))); + D8.optimize(appView, options, timing, executor); List<Marker> markers = appView.dexItemFactory().extractMarkers(); @@ -99,9 +103,7 @@ assert !options.hasMethodsFilter(); ApplicationWriter writer = new ApplicationWriter( - appView.appInfo().app(), - null, - options, + appView, markers, GraphLens.getIdentityLens(), InitClassLens.getDefault(),
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java index 9935d84..8b5d011 100644 --- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java +++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -19,6 +19,7 @@ import com.android.tools.r8.graph.LazyLoadedDexApplication; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.NamingLens; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.ExceptionUtils; import com.android.tools.r8.utils.FeatureClassMapping; import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException; @@ -71,8 +72,10 @@ try { Timing timing = new Timing("DexSplitter"); - DexApplication app = - new ApplicationReader(command.getInputApp(), options, timing).read(null, executor); + ApplicationReader applicationReader = + new ApplicationReader(command.getInputApp(), options, timing); + DexApplication app = applicationReader.read(executor); + MainDexClasses mainDexClasses = applicationReader.readMainDexClasses(app); List<Marker> markers = app.dexItemFactory.extractMarkers(); @@ -83,13 +86,20 @@ Map<String, LazyLoadedDexApplication.Builder> applications = getDistribution(app, featureClassMapping, mapper); for (Entry<String, LazyLoadedDexApplication.Builder> entry : applications.entrySet()) { + String feature = entry.getKey(); DexApplication featureApp = entry.getValue().build(); assert !options.hasMethodsFilter(); - // Run d8 optimize to ensure jumbo strings are handled. - AppInfo appInfo = AppInfo.createInitialAppInfo(featureApp); + // If this is the base, we add the main dex list. + AppInfo appInfo = + feature.equals(featureClassMapping.getBaseName()) + ? AppInfo.createInitialAppInfo(featureApp, mainDexClasses) + : AppInfo.createInitialAppInfo(featureApp); AppView<AppInfo> appView = AppView.createForD8(appInfo); + + // Run d8 optimize to ensure jumbo strings are handled. D8.optimize(appView, options, timing, executor); + // We create a specific consumer for each split. Path outputDir = Paths.get(output).resolve(entry.getKey()); if (!Files.exists(outputDir)) { @@ -99,9 +109,7 @@ try { new ApplicationWriter( - appView.appInfo().app(), appView, - options, markers, GraphLens.getIdentityLens(), InitClassLens.getDefault(), @@ -134,10 +142,6 @@ LazyLoadedDexApplication.Builder featureApplication = applications.get(feature); if (featureApplication == null) { featureApplication = DexApplication.builder(app.options, app.timing); - // If this is the base, we add the main dex list. - if (feature.equals(featureClassMapping.getBaseName())) { - featureApplication.addToMainDexList(app.mainDexList); - } applications.put(feature, featureApplication); } featureApplication.addProgramClass(clazz);
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java index c8d6295..9492e12 100644 --- a/src/main/java/com/android/tools/r8/ExtractMarker.java +++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -103,8 +103,7 @@ InternalOptions options = new InternalOptions(); options.skipReadingDexCode = true; options.minApiLevel = AndroidApiLevel.P.getLevel(); - DexApplication dexApp = - new ApplicationReader(app, options, new Timing("ExtractMarker")).read(); + DexApplication dexApp = new ApplicationReader(app, options, new Timing("ExtractMarker")).read(); return dexApp.dexItemFactory.extractMarkers(); }
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java index 8144903..74da57f 100644 --- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java +++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -25,6 +25,7 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.DirectMappedDexApplication; import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.LazyLoadedDexApplication; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration; import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser; @@ -284,7 +285,7 @@ // Build a plain text file with the desugared APIs. List<String> desugaredApisSignatures = new ArrayList<>(); - DexApplication.Builder builder = DexApplication.builder(options, Timing.empty()); + LazyLoadedDexApplication.Builder builder = DexApplication.builder(options, Timing.empty()); supportedMethods.supportedMethods.forEach( (clazz, methods) -> { String classBinaryName = @@ -310,8 +311,7 @@ lintFile(compilationApiLevel, minApiLevel, ".txt"), desugaredApisSignatures); // Write a header jar with the desugared APIs. - AppInfo appInfo = AppInfo.createInitialAppInfo(builder.build()); - AppView<?> appView = AppView.createForD8(appInfo); + AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(builder.build())); CfApplicationWriter writer = new CfApplicationWriter( appView,
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java index 243b37a..04479b1 100644 --- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java +++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -16,8 +16,8 @@ import com.android.tools.r8.graph.SubtypingInfo; import com.android.tools.r8.shaking.Enqueuer; import com.android.tools.r8.shaking.EnqueuerFactory; -import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.shaking.MainDexListBuilder; +import com.android.tools.r8.shaking.MainDexTracingResult; import com.android.tools.r8.shaking.RootSetBuilder; import com.android.tools.r8.shaking.RootSetBuilder.RootSet; import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer; @@ -70,10 +70,10 @@ EnqueuerFactory.createForMainDexTracing(appView, subtypingInfo, graphConsumer); Set<DexProgramClass> liveTypes = enqueuer.traceMainDex(mainDexRootSet, executor, timing); // LiveTypes is the result. - MainDexClasses mainDexClasses = new MainDexListBuilder(liveTypes, appView).run(); + MainDexTracingResult mainDexTracingResult = new MainDexListBuilder(liveTypes, appView).run(); List<String> result = - mainDexClasses.getClasses().stream() + mainDexTracingResult.getClasses().stream() .map(c -> c.toSourceString().replace('.', '/') + ".class") .sorted() .collect(Collectors.toList()); @@ -88,7 +88,7 @@ () -> { ArrayList<DexProgramClass> classes = new ArrayList<>(); // TODO(b/131668850): This is not a deterministic order! - mainDexClasses + mainDexTracingResult .getClasses() .forEach( type -> {
diff --git a/src/main/java/com/android/tools/r8/JarSizeCompare.java b/src/main/java/com/android/tools/r8/JarSizeCompare.java index 83261a3..15e29fa 100644 --- a/src/main/java/com/android/tools/r8/JarSizeCompare.java +++ b/src/main/java/com/android/tools/r8/JarSizeCompare.java
@@ -53,7 +53,8 @@ + " --input <name2> <input2.jar> [<map2.txt>] ...\n" + "\n" + "JarSizeCompare outputs the class, method, field sizes of the given JAR files.\n" - + "For each input, a ProGuard map can be passed that is used to resolve minified names.\n"; + + "For each input, a ProGuard map can be passed that is used to resolve minified" + + " names.\n"; private static final ImmutableMap<String, String> R8_RELOCATIONS = ImmutableMap.<String, String>builder()
diff --git a/src/main/java/com/android/tools/r8/PrintClassList.java b/src/main/java/com/android/tools/r8/PrintClassList.java index 40cdf2e..73cb04d 100644 --- a/src/main/java/com/android/tools/r8/PrintClassList.java +++ b/src/main/java/com/android/tools/r8/PrintClassList.java
@@ -45,8 +45,7 @@ new ApplicationReader(builder.build(), new InternalOptions(), new Timing("PrintClassList")) .read( proguardMapFile == null ? null : StringResource.fromFile(proguardMapFile), - executorService - ); + executorService); ClassNameMapper map = application.getProguardMap(); for (DexProgramClass clazz : application.classes()) { System.out.print(maybeDeobfuscateType(map, clazz.type));
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java index 47ed5a0..7ffc5ae 100644 --- a/src/main/java/com/android/tools/r8/PrintUses.java +++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -25,6 +25,7 @@ import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.desugar.LambdaDescriptor; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.StringUtils; @@ -349,7 +350,9 @@ InternalOptions options = new InternalOptions(); application = new ApplicationReader(inputApp, options, new Timing("PrintUses")).read().toDirect(); - appInfo = AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(application); + appInfo = + AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy( + application, MainDexClasses.createEmptyMainDexClasses()); } private void analyze() {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index 3a9b0d9..7b94e97 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -91,6 +91,7 @@ import com.android.tools.r8.shaking.EnqueuerFactory; import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.shaking.MainDexListBuilder; +import com.android.tools.r8.shaking.MainDexTracingResult; import com.android.tools.r8.shaking.ProguardClassFilter; import com.android.tools.r8.shaking.ProguardConfigurationRule; import com.android.tools.r8.shaking.ProguardConfigurationUtils; @@ -231,9 +232,7 @@ .write(options.getClassFileConsumer()); } else { new ApplicationWriter( - appView.appInfo().app(), appView, - options, // Ensure that the marker for this compilation is the first in the list. ImmutableList.<Marker>builder().add(marker).addAll(markers).build(), graphLens, @@ -290,13 +289,14 @@ try { AppView<AppInfoWithClassHierarchy> appView; { - DirectMappedDexApplication application = - new ApplicationReader(inputApp, options, timing).read(executorService).toDirect(); + ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing); + DirectMappedDexApplication application = applicationReader.read(executorService).toDirect(); + MainDexClasses mainDexClasses = applicationReader.readMainDexClasses(application); // Now that the dex-application is fully loaded, close any internal archive providers. inputApp.closeInternalArchiveProviders(); - appView = AppView.createForR8(application); + appView = AppView.createForR8(application, mainDexClasses); appView.setAppServices(AppServices.builder(appView).build()); } @@ -451,7 +451,7 @@ // by certain optimizations to avoid introducing additional class references into main dex // classes, as that can cause the final number of main dex methods to grow. RootSet mainDexRootSet = null; - MainDexClasses mainDexClasses = MainDexClasses.NONE; + MainDexTracingResult mainDexTracingResult = MainDexTracingResult.NONE; if (!options.mainDexKeepRules.isEmpty()) { assert appView.graphLens().isIdentityLens(); // Find classes which may have code executed before secondary dex files installation. @@ -464,7 +464,7 @@ EnqueuerFactory.createForMainDexTracing(appView, subtypingInfo) .traceMainDex(mainDexRootSet, executorService, timing); // Calculate the automatic main dex list according to legacy multidex constraints. - mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, appView).run(); + mainDexTracingResult = new MainDexListBuilder(mainDexBaseClasses, appView).run(); appView.appInfo().unsetObsolete(); } @@ -523,7 +523,7 @@ if (options.enableStaticClassMerging) { timing.begin("HorizontalStaticClassMerger"); StaticClassMerger staticClassMerger = - new StaticClassMerger(appViewWithLiveness, options, mainDexClasses); + new StaticClassMerger(appViewWithLiveness, options, mainDexTracingResult); NestedGraphLens lens = staticClassMerger.run(); appView.rewriteWithLens(lens); timing.end(); @@ -536,7 +536,7 @@ appViewWithLiveness, executorService, timing, - mainDexClasses); + mainDexTracingResult); VerticalClassMergerGraphLens lens = verticalClassMerger.run(); if (lens != null) { appView.setVerticallyMergedClasses(verticalClassMerger.getMergedClasses()); @@ -548,7 +548,7 @@ timing.begin("HorizontalClassMerger"); HorizontalClassMerger merger = new HorizontalClassMerger( - appViewWithLiveness, mainDexClasses, classMergingEnqueuerExtension); + appViewWithLiveness, mainDexTracingResult, classMergingEnqueuerExtension); HorizontalClassMergerGraphLens lens = merger.run(); if (lens != null) { appView.setHorizontallyMergedClasses(lens.getHorizontallyMergedClasses()); @@ -613,7 +613,7 @@ timing.begin("Create IR"); CfgPrinter printer = options.printCfg ? new CfgPrinter() : null; try { - IRConverter converter = new IRConverter(appView, timing, printer, mainDexClasses); + IRConverter converter = new IRConverter(appView, timing, printer, mainDexTracingResult); DexApplication application = converter.optimize(executorService).asDirect(); appView.setAppInfo(appView.appInfo().rebuild(previous -> application)); } finally { @@ -660,8 +660,8 @@ Set<DexProgramClass> mainDexBaseClasses = enqueuer.traceMainDex(mainDexRootSet, executorService, timing); // Calculate the automatic main dex list according to legacy multidex constraints. - mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, appView).run(); - final MainDexClasses finalMainDexClasses = mainDexClasses; + mainDexTracingResult = new MainDexListBuilder(mainDexBaseClasses, appView).run(); + final MainDexTracingResult finalMainDexClasses = mainDexTracingResult; processWhyAreYouKeepingAndCheckDiscarded( mainDexRootSet, @@ -772,9 +772,10 @@ .setClassesToRetainInnerClassAttributeFor(classesToRetainInnerClassAttributeFor) .build(appView.withLiveness(), removedClasses) .run(); - if (!mainDexClasses.isEmpty()) { + if (!mainDexTracingResult.isEmpty()) { // Remove types that no longer exists from the computed main dex list. - mainDexClasses = mainDexClasses.prunedCopy(appView.appInfo().withLiveness()); + mainDexTracingResult = + mainDexTracingResult.prunedCopy(appView.appInfo().withLiveness()); } // Synthesize fields for triggering class initializers. @@ -785,7 +786,7 @@ } if (appView.options().protoShrinking().isProtoShrinkingEnabled()) { - IRConverter converter = new IRConverter(appView, timing, null, mainDexClasses); + IRConverter converter = new IRConverter(appView, timing, null, mainDexTracingResult); // If proto shrinking is enabled, we need to reprocess every dynamicMethod(). This ensures // that proto fields that have been removed by the second round of tree shaking are also @@ -872,17 +873,7 @@ // Add automatic main dex classes to an eventual manual list of classes. if (!options.mainDexKeepRules.isEmpty()) { - MainDexClasses finalMainDexClasses = mainDexClasses; - appView.setAppInfo( - appView - .appInfo() - .rebuild( - application -> - application - .builder() - .addToMainDexList(finalMainDexClasses.getClasses()) - .build() - .asDirect())); + appView.appInfo().getMainDexClasses().addAll(mainDexTracingResult); } // Validity checks.
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java index 80dd656..0dcca76 100644 --- a/src/main/java/com/android/tools/r8/bisect/Bisect.java +++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -189,9 +189,7 @@ AndroidAppConsumers compatSink = new AndroidAppConsumers(options); ApplicationWriter writer = new ApplicationWriter( - app, AppView.createForD8(AppInfo.createInitialAppInfo(app)), - options, null, null, InitClassLens.getDefault(),
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 b679a54..f128f76 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -131,7 +134,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getAsmOpcode()); }
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 6510e23..5757b8c 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -21,7 +24,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(Opcodes.ARRAYLENGTH); }
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 a9d754e..7993e8e 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,15 +5,18 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.MemberType; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -58,7 +61,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getLoadType()); }
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 5e8c152..1c16397 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.MemberType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -56,7 +59,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getStoreType()); }
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 7f6a380..e263d02 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
@@ -5,15 +5,18 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexClassAndMethod; +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.GraphLens; 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; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -34,8 +37,15 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - visitor.visitTypeInsn(Opcodes.CHECKCAST, lens.lookupInternalName(graphLens.lookupType(type))); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexType rewrittenType = graphLens.lookupType(type); + visitor.visitTypeInsn(Opcodes.CHECKCAST, namingLens.lookupInternalName(rewrittenType)); } @Override
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 1163483..1eeb6b4 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,9 +5,11 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Cmp; import com.android.tools.r8.ir.code.Cmp.Bias; import com.android.tools.r8.ir.code.NumericType; @@ -15,6 +17,7 @@ import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -81,7 +84,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getAsmOpcode()); }
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 37255ff..2bb2444 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
@@ -6,14 +6,17 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -34,10 +37,13 @@ @Override public void write( - MethodVisitor visitor, + ProgramMethod context, + DexItemFactory dexItemFactory, GraphLens graphLens, InitClassLens initClassLens, - NamingLens namingLens) { + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitLdcInsn(Type.getObjectType(getInternalName(graphLens, namingLens))); } @@ -52,10 +58,11 @@ } private String getInternalName(GraphLens graphLens, NamingLens namingLens) { - switch (type.toShorty()) { + DexType rewrittenType = graphLens.lookupType(type); + switch (rewrittenType.toShorty()) { case '[': case 'L': - return namingLens.lookupInternalName(graphLens.lookupType(type)); + return namingLens.lookupInternalName(rewrittenType); case 'Z': return "java/lang/Boolean/TYPE"; case 'B': @@ -73,7 +80,7 @@ case 'D': return "java/lang/Double/TYPE"; default: - throw new Unreachable("Unexpected type in const-class: " + type); + throw new Unreachable("Unexpected type in const-class: " + rewrittenType); } }
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 c5d52f2..d058eca 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
@@ -5,15 +5,18 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; 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.graph.UseRegistry.MethodHandleUse; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -33,8 +36,17 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - visitor.visitLdcInsn(handle.toAsmHandle(lens)); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexMethodHandle rewrittenHandle = + rewriter.rewriteDexMethodHandle( + handle, MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context); + visitor.visitLdcInsn(rewrittenHandle.toAsmHandle(namingLens)); } @Override
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 17577b9..e59a64e 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
@@ -5,14 +5,17 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -33,8 +36,15 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - visitor.visitLdcInsn(Type.getType(type.toDescriptorString(lens))); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexProto rewrittenType = rewriter.rewriteProto(getType()); + visitor.visitLdcInsn(Type.getType(rewrittenType.toDescriptorString(namingLens))); } @Override
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 1c5e970..e5740e7 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -21,7 +24,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(Opcodes.ACONST_NULL); }
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 b4e63a9..642eeb9 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,13 +5,16 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -58,7 +61,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { switch (type) { case INT: {
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 649f756..9037875 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -44,7 +47,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitLdcInsn(string.toString()); }
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 79e59db..bdc470f 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
@@ -6,14 +6,17 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -50,7 +53,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { throw new Unreachable( "CfDexItemBasedConstString instructions should always be rewritten into CfConstString"); }
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 32c8494..3cff4ee 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
@@ -7,15 +7,18 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; 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; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -55,12 +58,18 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - DexField newField = graphLens.lookupField(field); - DexField newDeclaringField = graphLens.lookupField(declaringField); - String owner = lens.lookupInternalName(newField.holder); - String name = lens.lookupName(newDeclaringField).toString(); - String desc = lens.lookupDescriptor(newField.type).toString(); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexField rewrittenField = graphLens.lookupField(field); + DexField rewrittenDeclaringField = graphLens.lookupField(declaringField); + String owner = namingLens.lookupInternalName(rewrittenField.holder); + String name = namingLens.lookupName(rewrittenDeclaringField).toString(); + String desc = namingLens.lookupDescriptor(rewrittenField.type).toString(); visitor.visitFieldInsn(opcode, owner, name, desc); }
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 152f9e9..f392338 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
@@ -12,9 +12,11 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -44,7 +46,7 @@ return Top.SINGLETON; } - abstract Object getTypeOpcode(NamingLens lens); + abstract Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens); public boolean isWide() { return false; @@ -102,13 +104,14 @@ } @Override - Object getTypeOpcode(NamingLens lens) { - if (type == DexItemFactory.nullValueType) { + Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) { + DexType rewrittenType = graphLens.lookupType(type); + if (rewrittenType == DexItemFactory.nullValueType) { return Opcodes.NULL; } - switch (type.toShorty()) { + switch (rewrittenType.toShorty()) { case 'L': - return lens.lookupInternalName(type); + return namingLens.lookupInternalName(rewrittenType); case 'I': return Opcodes.INTEGER; case 'F': @@ -118,7 +121,7 @@ case 'D': return Opcodes.DOUBLE; default: - throw new Unreachable("Unexpected value type: " + type); + throw new Unreachable("Unexpected value type: " + rewrittenType); } } @@ -148,7 +151,7 @@ } @Override - Object getTypeOpcode(NamingLens lens) { + Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) { return Opcodes.TOP; } @@ -171,7 +174,7 @@ } @Override - Object getTypeOpcode(NamingLens lens) { + Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) { return label.getLabel(); } @@ -190,7 +193,7 @@ private UninitializedThis() {} @Override - Object getTypeOpcode(NamingLens lens) { + Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) { return Opcodes.UNINITIALIZED_THIS; } @@ -225,11 +228,17 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { int stackCount = computeStackCount(); - Object[] stackTypes = computeStackTypes(stackCount, lens); + Object[] stackTypes = computeStackTypes(stackCount, graphLens, namingLens); int localsCount = computeLocalsCount(); - Object[] localsTypes = computeLocalsTypes(localsCount, lens); + Object[] localsTypes = computeLocalsTypes(localsCount, graphLens, namingLens); visitor.visitFrame(F_NEW, localsCount, localsTypes, stackCount, stackTypes); } @@ -237,14 +246,14 @@ return stack.size(); } - private Object[] computeStackTypes(int stackCount, NamingLens lens) { + private Object[] computeStackTypes(int stackCount, GraphLens graphLens, NamingLens namingLens) { assert stackCount == stack.size(); if (stackCount == 0) { return null; } Object[] stackTypes = new Object[stackCount]; for (int i = 0; i < stackCount; i++) { - stackTypes[i] = stack.get(i).getTypeOpcode(lens); + stackTypes[i] = stack.get(i).getTypeOpcode(graphLens, namingLens); } return stackTypes; } @@ -266,7 +275,7 @@ return localsCount; } - private Object[] computeLocalsTypes(int localsCount, NamingLens lens) { + private Object[] computeLocalsTypes(int localsCount, GraphLens graphLens, NamingLens namingLens) { if (localsCount == 0) { return null; } @@ -275,7 +284,8 @@ int localIndex = 0; for (int i = 0; i <= maxRegister; i++) { FrameType type = locals.get(i); - localsTypes[localIndex++] = type == null ? Opcodes.TOP : type.getTypeOpcode(lens); + localsTypes[localIndex++] = + type == null ? Opcodes.TOP : type.getTypeOpcode(graphLens, namingLens); if (type != null && type.isWide()) { i++; }
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 d38c0fe..0cd79d4 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,12 +4,15 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -46,7 +49,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitJumpInsn(Opcodes.GOTO, target.getLabel()); }
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 f64d79c..31497fd 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,15 +5,18 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.If.Type; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -71,7 +74,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitJumpInsn(getOpcode(), target.getLabel()); }
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 1ee17b1..47cbcad 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,15 +5,18 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.If.Type; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -71,7 +74,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitJumpInsn(getOpcode(), target.getLabel()); }
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 edba7b4..4a37601 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -28,7 +31,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitIincInsn(var, increment); }
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 afcae7d..b12d10e 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
@@ -6,14 +6,17 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -39,11 +42,20 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - DexField field = initClassLens.getInitClassField(clazz); - String owner = lens.lookupInternalName(field.holder); - String name = lens.lookupName(field).toString(); - String desc = lens.lookupDescriptor(field.type).toString(); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + // We intentionally apply the graph lens first, and then the init class lens, using the fact + // that the init class lens maps classes in the final program to fields in the final program. + DexType rewrittenClass = graphLens.lookupType(clazz); + DexField clinitField = initClassLens.getInitClassField(rewrittenClass); + String owner = namingLens.lookupInternalName(clinitField.holder); + String name = namingLens.lookupName(clinitField).toString(); + String desc = namingLens.lookupDescriptor(clinitField.type).toString(); visitor.visitFieldInsn(OPCODE, owner, name, desc); }
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 fc26a95..c34d576 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
@@ -5,14 +5,17 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexClassAndMethod; +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.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -43,8 +46,15 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - visitor.visitTypeInsn(Opcodes.INSTANCEOF, lens.lookupInternalName(type)); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexType rewrittenType = graphLens.lookupType(getType()); + visitor.visitTypeInsn(Opcodes.INSTANCEOF, namingLens.lookupInternalName(rewrittenType)); } @Override
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 16ef22f..da09f7b 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.ClasspathMethod; import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; @@ -14,6 +15,7 @@ import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -22,7 +24,13 @@ public abstract class CfInstruction { public abstract void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor); public abstract void print(CfPrinter printer);
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 3851031..4f21538 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
@@ -11,6 +11,7 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; @@ -18,6 +19,7 @@ import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; 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.code.Invoke; import com.android.tools.r8.ir.code.Invoke.Type; @@ -26,6 +28,7 @@ import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -72,12 +75,20 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - DexMethod newMethod = graphLens.lookupMethod(method); - String owner = lens.lookupInternalName(newMethod.holder); - String name = lens.lookupName(newMethod).toString(); - String desc = newMethod.proto.toDescriptorString(lens); - visitor.visitMethodInsn(opcode, owner, name, desc, itf); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(method, context.getReference(), getInvokeType(context)); + DexMethod rewrittenMethod = lookup.getMethod(); + String owner = namingLens.lookupInternalName(rewrittenMethod.holder); + String name = namingLens.lookupName(rewrittenMethod).toString(); + String desc = rewrittenMethod.proto.toDescriptorString(namingLens); + visitor.visitMethodInsn(lookup.getType().getCfOpcode(), owner, name, desc, itf); } @Override @@ -87,25 +98,46 @@ @Override void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { - switch (opcode) { - case Opcodes.INVOKEINTERFACE: + Type invokeType = getInvokeType(context); + switch (invokeType) { + case DIRECT: + registry.registerInvokeDirect(method); + break; + case INTERFACE: registry.registerInvokeInterface(method); break; - case Opcodes.INVOKEVIRTUAL: - registry.registerInvokeVirtual(method); - break; - case Opcodes.INVOKESPECIAL: - if (method.name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME)) { - registry.registerInvokeDirect(method); - } else if (method.holder == context.getHolderType()) { - registry.registerInvokeDirect(method); - } else { - registry.registerInvokeSuper(method); - } - break; - case Opcodes.INVOKESTATIC: + case STATIC: registry.registerInvokeStatic(method); break; + case SUPER: + registry.registerInvokeSuper(method); + break; + case VIRTUAL: + registry.registerInvokeVirtual(method); + break; + default: + throw new Unreachable("Unexpected invoke type " + invokeType); + } + } + + private Invoke.Type getInvokeType(DexClassAndMethod context) { + switch (opcode) { + case Opcodes.INVOKEINTERFACE: + return Type.INTERFACE; + + case Opcodes.INVOKEVIRTUAL: + return Type.VIRTUAL; + + case Opcodes.INVOKESPECIAL: + if (method.name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME) + || method.holder == context.getHolderType()) { + return Type.DIRECT; + } + return Type.SUPER; + + case Opcodes.INVOKESTATIC: + return Type.STATIC; + default: throw new Unreachable("unknown CfInvoke opcode " + opcode); }
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 f57046b..a455305 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
@@ -7,6 +7,7 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; @@ -14,11 +15,13 @@ import com.android.tools.r8.graph.DexValue; import com.android.tools.r8.graph.GraphLens; 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.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -38,17 +41,27 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - DexMethodHandle bootstrapMethod = callSite.bootstrapMethod; - List<DexValue> bootstrapArgs = callSite.bootstrapArgs; + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexCallSite rewrittenCallSite = rewriter.rewriteCallSite(callSite, context); + DexMethodHandle bootstrapMethod = rewrittenCallSite.bootstrapMethod; + List<DexValue> bootstrapArgs = rewrittenCallSite.bootstrapArgs; Object[] bsmArgs = new Object[bootstrapArgs.size()]; for (int i = 0; i < bootstrapArgs.size(); i++) { - bsmArgs[i] = decodeBootstrapArgument(bootstrapArgs.get(i), lens); + bsmArgs[i] = decodeBootstrapArgument(bootstrapArgs.get(i), namingLens); } - Handle bsmHandle = bootstrapMethod.toAsmHandle(lens); - DexString methodName = lens.lookupMethodName(callSite); + Handle bsmHandle = bootstrapMethod.toAsmHandle(namingLens); + DexString methodName = namingLens.lookupMethodName(rewrittenCallSite); visitor.visitInvokeDynamicInsn( - methodName.toString(), callSite.methodProto.toDescriptorString(lens), bsmHandle, bsmArgs); + methodName.toString(), + rewrittenCallSite.methodProto.toDescriptorString(namingLens), + bsmHandle, + bsmArgs); } private Object decodeBootstrapArgument(DexValue value, NamingLens lens) {
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 88659de..47ee09b 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,12 +5,15 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -31,7 +34,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { 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 19ba74a..b27fd00 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,12 +4,15 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -44,7 +47,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitLabel(getLabel()); }
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 80bb1da..17e0ecd 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -58,7 +61,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitVarInsn(getLoadType(), var); }
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 0f5bd4e..19a3bfe 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -106,7 +109,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getAsmOpcode()); }
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 ebefa78..24b580b 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,14 +4,17 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Monitor.Type; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -32,7 +35,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(type == Type.ENTER ? Opcodes.MONITORENTER : Opcodes.MONITOREXIT); }
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 69a69af..33f4244 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
@@ -5,14 +5,17 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexClassAndMethod; +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.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -39,8 +42,15 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - visitor.visitMultiANewArrayInsn(lens.lookupInternalName(type), dimensions); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexType rewrittenType = graphLens.lookupType(getType()); + visitor.visitMultiANewArrayInsn(namingLens.lookupInternalName(rewrittenType), dimensions); } @Override
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 32ef906..88274b3 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -33,7 +36,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getAsmOpcode()); }
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 e0b8785..83b7e63 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
@@ -5,14 +5,17 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexClassAndMethod; +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.GraphLens; 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; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -33,8 +36,15 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { - visitor.visitTypeInsn(Opcodes.NEW, lens.lookupInternalName(type)); + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexType rewrittenType = graphLens.lookupType(getType()); + visitor.visitTypeInsn(Opcodes.NEW, namingLens.lookupInternalName(rewrittenType)); } @Override
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 6c3869b..3c9a746 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
@@ -6,15 +6,18 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; 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; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -58,21 +61,36 @@ } } - private String getElementInternalName(NamingLens lens) { + private String getElementInternalName( + DexItemFactory dexItemFactory, GraphLens graphLens, NamingLens namingLens) { assert !type.isPrimitiveArrayType(); - String renamedArrayType = lens.lookupDescriptor(type).toString(); - assert renamedArrayType.charAt(0) == '['; - String elementType = renamedArrayType.substring(1); - return DescriptorUtils.descriptorToInternalName(elementType); + StringBuilder renamedElementDescriptor = new StringBuilder(); + // Intentionally starting from 1 to get the element descriptor. + int numberOfLeadingSquareBrackets = getType().getNumberOfLeadingSquareBrackets(); + for (int i = 1; i < numberOfLeadingSquareBrackets; i++) { + renamedElementDescriptor.append("["); + } + DexType baseType = getType().toBaseType(dexItemFactory); + DexType rewrittenBaseType = graphLens.lookupType(baseType); + renamedElementDescriptor.append( + namingLens.lookupDescriptor(rewrittenBaseType).toSourceString()); + return DescriptorUtils.descriptorToInternalName(renamedElementDescriptor.toString()); } @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { if (type.isPrimitiveArrayType()) { visitor.visitIntInsn(Opcodes.NEWARRAY, getPrimitiveTypeCode()); } else { - visitor.visitTypeInsn(Opcodes.ANEWARRAY, getElementInternalName(lens)); + visitor.visitTypeInsn( + Opcodes.ANEWARRAY, getElementInternalName(dexItemFactory, graphLens, namingLens)); } }
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 18a2ae6..e2b6044 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,12 +4,15 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -20,7 +23,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(Opcodes.NOP); }
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 405fb42..ce3ab3b 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -43,7 +46,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(this.getAsmOpcode()); }
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 70a3f07..e30be70 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Position; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -28,7 +31,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitLineNumber(position.line, label.getLabel()); }
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 d66d6cf..c5198d1 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -55,7 +58,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(getOpcode()); }
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 83b5e60..8f7bb37 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,12 +4,15 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -25,7 +28,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(Opcodes.RETURN); }
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 a4ecce6..a7a39b6 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,14 +6,17 @@ 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.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -77,7 +80,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(opcode.opcode); }
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 c3ce5db..d46d3a3 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,14 +5,17 @@ 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.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -58,7 +61,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitVarInsn(getStoreType(), var); }
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 3a3c72e..edc5244 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -71,7 +74,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { Label[] labels = new Label[targets.size()]; for (int i = 0; i < targets.size(); i++) { labels[i] = targets.get(i).getLabel();
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 3b49cb0..aaa7280 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,13 +4,16 @@ package com.android.tools.r8.cf.code; import com.android.tools.r8.cf.CfPrinter; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; import com.android.tools.r8.ir.conversion.CfState.Slot; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; @@ -26,7 +29,13 @@ @Override public void write( - MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + ProgramMethod context, + DexItemFactory dexItemFactory, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { visitor.visitInsn(Opcodes.ATHROW); }
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/code/CheckCast.java index 569b358..6ca2dc5 100644 --- a/src/main/java/com/android/tools/r8/code/CheckCast.java +++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -5,9 +5,12 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; public class CheckCast extends Format21c<DexType> { @@ -39,8 +42,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstClass.java b/src/main/java/com/android/tools/r8/code/ConstClass.java index 2f8f7db..ec8a13a 100644 --- a/src/main/java/com/android/tools/r8/code/ConstClass.java +++ b/src/main/java/com/android/tools/r8/code/ConstClass.java
@@ -5,9 +5,12 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; public class ConstClass extends Format21c<DexType> { @@ -39,8 +42,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java index 8518946..75fc2dc 100644 --- a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java +++ b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
@@ -6,11 +6,14 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.errors.InternalCompilerError; import com.android.tools.r8.graph.DexMethodHandle; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.graph.UseRegistry.MethodHandleUse; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -64,17 +67,33 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { - int index = BBBB.getOffset(mapping); + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexMethodHandle rewritten = + rewriter.rewriteDexMethodHandle( + getMethodHandle(), MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context); + int index = rewritten.getOffset(mapping); if (index != (index & 0xffff)) { throw new InternalCompilerError("MethodHandle-index overflow."); } - super.write(dest, mapping); + writeFirst(AA, dest); + write16BitReference(rewritten, dest, mapping); } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getMethodHandle().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexMethodHandle rewritten = + rewriter.rewriteDexMethodHandle( + getMethodHandle(), MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/code/ConstMethodType.java index 8eb5443..4767025 100644 --- a/src/main/java/com/android/tools/r8/code/ConstMethodType.java +++ b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
@@ -6,10 +6,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.errors.InternalCompilerError; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -62,17 +65,29 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { - int index = BBBB.getOffset(mapping); + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexProto rewritten = rewriter.rewriteProto(getMethodType()); + int index = rewritten.getOffset(mapping); if (index != (index & 0xffff)) { throw new InternalCompilerError("MethodType-index overflow."); } - super.write(dest, mapping); + writeFirst(AA, dest); + write16BitReference(rewritten, dest, mapping); } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getMethodType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexProto rewritten = rewriter.rewriteProto(getMethodType()); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstString.java b/src/main/java/com/android/tools/r8/code/ConstString.java index 261016b..8bccec9 100644 --- a/src/main/java/com/android/tools/r8/code/ConstString.java +++ b/src/main/java/com/android/tools/r8/code/ConstString.java
@@ -6,9 +6,12 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.errors.InternalCompilerError; import com.android.tools.r8.graph.DexString; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -31,7 +34,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { getString().collectIndexedItems(indexedItems); } @@ -71,12 +78,17 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { int index = BBBB.getOffset(mapping); if (index != (index & 0xffff)) { throw new InternalCompilerError("String-index overflow."); } - super.write(dest, mapping); + super.write(dest, context, graphLens, mapping, rewriter); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/DexInitClass.java b/src/main/java/com/android/tools/r8/code/DexInitClass.java index 20f2047..52cd9e1 100644 --- a/src/main/java/com/android/tools/r8/code/DexInitClass.java +++ b/src/main/java/com/android/tools/r8/code/DexInitClass.java
@@ -8,10 +8,13 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.code.FieldMemberType; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -36,9 +39,16 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - DexField field = indexedItems.getInitClassLens().getInitClassField(clazz); - field.collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + // We intentionally apply the graph lens first, and then the init class lens, using the fact + // that the init class lens maps classes in the final program to fields in the final program. + DexType rewrittenClass = graphLens.lookupType(clazz); + DexField clinitField = indexedItems.getInitClassLens().getInitClassField(rewrittenClass); + clinitField.collectIndexedItems(indexedItems); } @Override @@ -91,10 +101,18 @@ } @Override - public void write(ShortBuffer buffer, ObjectToOffsetMapping mapping) { - DexField field = mapping.getClinitField(clazz); - writeFirst(dest, buffer, getOpcode(field)); - write16BitReference(field, buffer, mapping); + public void write( + ShortBuffer buffer, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + // We intentionally apply the graph lens first, and then the init class lens, using the fact + // that the init class lens maps classes in the final program to fields in the final program. + DexType rewrittenClass = graphLens.lookupType(clazz); + DexField clinitField = mapping.getClinitField(rewrittenClass); + writeFirst(dest, buffer, getOpcode(clinitField)); + write16BitReference(clinitField, buffer, mapping); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java index 1fb6e8c..c50bba8 100644 --- a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java +++ b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
@@ -6,9 +6,12 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexReference; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo; import java.nio.ShortBuffer; @@ -35,7 +38,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { getItem().collectIndexedItems(indexedItems); } @@ -78,7 +85,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { throw new Unreachable( "DexItemBasedConstString instructions should always be rewritten into ConstString"); }
diff --git a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java b/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java index 36338f9..20d412f 100644 --- a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java +++ b/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
@@ -3,8 +3,11 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -42,12 +45,17 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(3, dest); // Pseudo-opcode = 0x0300 write16BitValue(element_width, dest); write32BitValue(size, dest); - for (int i = 0; i < data.length; i++) { - write16BitValue(data[i], dest); + for (short datum : data) { + write16BitValue(datum, dest); } }
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArray.java b/src/main/java/com/android/tools/r8/code/FilledNewArray.java index 1932e16..5198876 100644 --- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java +++ b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
@@ -5,8 +5,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public class FilledNewArray extends Format35c<DexType> { @@ -38,8 +43,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } public DexType getType() { @@ -55,4 +65,17 @@ public boolean canThrow() { return true; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + writeFirst(A, G, dest); + write16BitReference(rewritten, dest, mapping); + write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest); + } }
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java index 7fc2adc..de651f5 100644 --- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java +++ b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
@@ -5,8 +5,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public class FilledNewArrayRange extends Format3rc<DexType> { @@ -38,8 +43,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } public DexType getType() { @@ -55,4 +65,17 @@ public boolean canThrow() { return true; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + writeFirst(AA, dest); + write16BitReference(rewritten, dest, mapping); + write16BitValue(CCCC, dest); + } }
diff --git a/src/main/java/com/android/tools/r8/code/Format10t.java b/src/main/java/com/android/tools/r8/code/Format10t.java index 4c61fa3..d34ecb2 100644 --- a/src/main/java/com/android/tools/r8/code/Format10t.java +++ b/src/main/java/com/android/tools/r8/code/Format10t.java
@@ -4,7 +4,10 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -25,7 +28,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); } @@ -53,7 +61,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format10x.java b/src/main/java/com/android/tools/r8/code/Format10x.java index 8eed571..6ffc866 100644 --- a/src/main/java/com/android/tools/r8/code/Format10x.java +++ b/src/main/java/com/android/tools/r8/code/Format10x.java
@@ -4,7 +4,10 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -20,7 +23,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(0, dest); } @@ -45,7 +53,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format11n.java b/src/main/java/com/android/tools/r8/code/Format11n.java index f2b8ac2..933beba 100644 --- a/src/main/java/com/android/tools/r8/code/Format11n.java +++ b/src/main/java/com/android/tools/r8/code/Format11n.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -34,7 +37,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(B, A, dest); } @@ -58,7 +66,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format11x.java b/src/main/java/com/android/tools/r8/code/Format11x.java index 318bf04..5d627bd 100644 --- a/src/main/java/com/android/tools/r8/code/Format11x.java +++ b/src/main/java/com/android/tools/r8/code/Format11x.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -25,7 +28,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); } @@ -53,7 +61,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format12x.java b/src/main/java/com/android/tools/r8/code/Format12x.java index ac90623..36284b9 100644 --- a/src/main/java/com/android/tools/r8/code/Format12x.java +++ b/src/main/java/com/android/tools/r8/code/Format12x.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -28,7 +31,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(B, A, dest); } @@ -57,7 +65,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format20t.java b/src/main/java/com/android/tools/r8/code/Format20t.java index f145476..42d172a 100644 --- a/src/main/java/com/android/tools/r8/code/Format20t.java +++ b/src/main/java/com/android/tools/r8/code/Format20t.java
@@ -4,7 +4,10 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -24,7 +27,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(0, dest); write16BitValue(AAAA, dest); } @@ -53,7 +61,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format21c.java b/src/main/java/com/android/tools/r8/code/Format21c.java index 04848f0..9118072 100644 --- a/src/main/java/com/android/tools/r8/code/Format21c.java +++ b/src/main/java/com/android/tools/r8/code/Format21c.java
@@ -4,8 +4,11 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.Constants; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; import java.util.function.BiPredicate; @@ -29,7 +32,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitReference(BBBB, dest, mapping); }
diff --git a/src/main/java/com/android/tools/r8/code/Format21h.java b/src/main/java/com/android/tools/r8/code/Format21h.java index 221dc9e..848990d 100644 --- a/src/main/java/com/android/tools/r8/code/Format21h.java +++ b/src/main/java/com/android/tools/r8/code/Format21h.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import java.nio.ShortBuffer; abstract class Format21h extends Base2Format { @@ -28,7 +31,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitValue(BBBB, dest); } @@ -48,7 +56,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format21s.java b/src/main/java/com/android/tools/r8/code/Format21s.java index a9d7dc1..31c4bc9 100644 --- a/src/main/java/com/android/tools/r8/code/Format21s.java +++ b/src/main/java/com/android/tools/r8/code/Format21s.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -30,7 +33,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitValue(BBBB, dest); } @@ -60,7 +68,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format21t.java b/src/main/java/com/android/tools/r8/code/Format21t.java index d89b029..5e52bac 100644 --- a/src/main/java/com/android/tools/r8/code/Format21t.java +++ b/src/main/java/com/android/tools/r8/code/Format21t.java
@@ -5,10 +5,13 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.If.Type; import com.android.tools.r8.ir.code.ValueTypeConstraint; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -32,7 +35,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitValue(BBBB, dest); } @@ -78,7 +86,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format22b.java b/src/main/java/com/android/tools/r8/code/Format22b.java index 3952eb7..48955dc 100644 --- a/src/main/java/com/android/tools/r8/code/Format22b.java +++ b/src/main/java/com/android/tools/r8/code/Format22b.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -34,7 +37,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitValue(combineBytes(CC, BB), dest); } @@ -65,7 +73,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format22c.java b/src/main/java/com/android/tools/r8/code/Format22c.java index 751ef61..0ff7841 100644 --- a/src/main/java/com/android/tools/r8/code/Format22c.java +++ b/src/main/java/com/android/tools/r8/code/Format22c.java
@@ -4,13 +4,12 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.Constants; +import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.IndexedDexItem; -import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; -import java.nio.ShortBuffer; import java.util.function.BiPredicate; -public abstract class Format22c<T extends IndexedDexItem> extends Base2Format { +public abstract class Format22c<T extends DexReference> extends Base2Format { public final byte A; public final byte B; @@ -33,12 +32,6 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { - writeFirst(B, A, dest); - write16BitReference(CCCC, dest, mapping); - } - - @Override public final int hashCode() { return ((CCCC.hashCode() << 8) | (A << 4) | B) ^ getClass().hashCode(); }
diff --git a/src/main/java/com/android/tools/r8/code/Format22s.java b/src/main/java/com/android/tools/r8/code/Format22s.java index 25c51d6..1b9aeb4 100644 --- a/src/main/java/com/android/tools/r8/code/Format22s.java +++ b/src/main/java/com/android/tools/r8/code/Format22s.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -34,7 +37,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(B, A, dest); write16BitValue(CCCC, dest); } @@ -65,7 +73,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format22t.java b/src/main/java/com/android/tools/r8/code/Format22t.java index 6505e5c..4e75d23 100644 --- a/src/main/java/com/android/tools/r8/code/Format22t.java +++ b/src/main/java/com/android/tools/r8/code/Format22t.java
@@ -5,10 +5,13 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.If.Type; import com.android.tools.r8.ir.code.ValueTypeConstraint; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -36,7 +39,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(B, A, dest); write16BitValue(CCCC, dest); } @@ -82,7 +90,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format22x.java b/src/main/java/com/android/tools/r8/code/Format22x.java index 5c1b2c4..901af1e 100644 --- a/src/main/java/com/android/tools/r8/code/Format22x.java +++ b/src/main/java/com/android/tools/r8/code/Format22x.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -29,7 +32,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitValue(BBBB, dest); } @@ -59,7 +67,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format23x.java b/src/main/java/com/android/tools/r8/code/Format23x.java index 739b66f..e9d030b 100644 --- a/src/main/java/com/android/tools/r8/code/Format23x.java +++ b/src/main/java/com/android/tools/r8/code/Format23x.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -33,7 +36,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write16BitValue(combineBytes(CC, BB), dest); } @@ -63,7 +71,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format30t.java b/src/main/java/com/android/tools/r8/code/Format30t.java index bfcf0d3..dcf5064 100644 --- a/src/main/java/com/android/tools/r8/code/Format30t.java +++ b/src/main/java/com/android/tools/r8/code/Format30t.java
@@ -4,7 +4,10 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -23,7 +26,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(0, dest); write32BitValue(AAAAAAAA, dest); } @@ -52,7 +60,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format31c.java b/src/main/java/com/android/tools/r8/code/Format31c.java index ead4920..023aeac 100644 --- a/src/main/java/com/android/tools/r8/code/Format31c.java +++ b/src/main/java/com/android/tools/r8/code/Format31c.java
@@ -7,8 +7,11 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexString; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; import java.util.function.BiPredicate; @@ -32,7 +35,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write32BitReference(BBBBBBBB, dest, mapping); } @@ -58,7 +66,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { BBBBBBBB.collectIndexedItems(indexedItems); }
diff --git a/src/main/java/com/android/tools/r8/code/Format31i.java b/src/main/java/com/android/tools/r8/code/Format31i.java index 5e55ca4..843319b 100644 --- a/src/main/java/com/android/tools/r8/code/Format31i.java +++ b/src/main/java/com/android/tools/r8/code/Format31i.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -28,7 +31,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write32BitValue(BBBBBBBB, dest); } @@ -53,7 +61,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format31t.java b/src/main/java/com/android/tools/r8/code/Format31t.java index d650fed..9c7fdfd 100644 --- a/src/main/java/com/android/tools/r8/code/Format31t.java +++ b/src/main/java/com/android/tools/r8/code/Format31t.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -28,7 +31,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); assert (getOffset() + BBBBBBBB) % 2 == 0; write32BitValue(BBBBBBBB, dest); @@ -68,7 +76,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format32x.java b/src/main/java/com/android/tools/r8/code/Format32x.java index a31a494..34ecf4f 100644 --- a/src/main/java/com/android/tools/r8/code/Format32x.java +++ b/src/main/java/com/android/tools/r8/code/Format32x.java
@@ -6,7 +6,10 @@ import static com.android.tools.r8.dex.Constants.U16BIT_MAX; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -30,7 +33,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(0, dest); write16BitValue(AAAA, dest); write16BitValue(BBBB, dest); @@ -61,7 +69,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Format35c.java b/src/main/java/com/android/tools/r8/code/Format35c.java index fba7d0d..8c2cb22 100644 --- a/src/main/java/com/android/tools/r8/code/Format35c.java +++ b/src/main/java/com/android/tools/r8/code/Format35c.java
@@ -5,9 +5,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.IndexedDexItem; -import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; -import java.nio.ShortBuffer; import java.util.function.BiPredicate; public abstract class Format35c<T extends IndexedDexItem> extends Base3Format { @@ -51,13 +49,6 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { - writeFirst(A, G, dest); - write16BitReference(BBBB, dest, mapping); - write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest); - } - - @Override public final int hashCode() { return ((BBBB.hashCode() << 24) | (A << 20) | (C << 16) | (D << 12) | (E << 8) | (F << 4) | G) ^ getClass().hashCode();
diff --git a/src/main/java/com/android/tools/r8/code/Format3rc.java b/src/main/java/com/android/tools/r8/code/Format3rc.java index a50a9d9..98e78cc 100644 --- a/src/main/java/com/android/tools/r8/code/Format3rc.java +++ b/src/main/java/com/android/tools/r8/code/Format3rc.java
@@ -5,9 +5,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.IndexedDexItem; -import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; -import java.nio.ShortBuffer; import java.util.function.BiPredicate; public abstract class Format3rc<T extends IndexedDexItem> extends Base3Format { @@ -37,13 +35,6 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { - writeFirst(AA, dest); - write16BitReference(BBBB, dest, mapping); - write16BitValue(CCCC, dest); - } - - @Override public final int hashCode() { return ((CCCC << 24) | (BBBB.hashCode() << 4) | AA) ^ getClass().hashCode(); }
diff --git a/src/main/java/com/android/tools/r8/code/Format45cc.java b/src/main/java/com/android/tools/r8/code/Format45cc.java index f5123cf..f6820c8 100644 --- a/src/main/java/com/android/tools/r8/code/Format45cc.java +++ b/src/main/java/com/android/tools/r8/code/Format45cc.java
@@ -8,8 +8,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.code.Invoke.Type; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -87,17 +92,36 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - BBBB.collectIndexedItems(indexedItems); - HHHH.collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC); + assert lookup.getType() == Type.POLYMORPHIC; + lookup.getMethod().collectIndexedItems(indexedItems); + + DexProto rewrittenProto = rewriter.rewriteProto(getProto()); + rewrittenProto.collectIndexedItems(indexedItems); } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC); + assert lookup.getType() == Type.POLYMORPHIC; writeFirst(A, G, dest); - write16BitReference(BBBB, dest, mapping); + write16BitReference(lookup.getMethod(), dest, mapping); write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest); - write16BitReference(HHHH, dest, mapping); + + DexProto rewrittenProto = rewriter.rewriteProto(getProto()); + write16BitReference(rewrittenProto, dest, mapping); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/Format4rcc.java b/src/main/java/com/android/tools/r8/code/Format4rcc.java index 0ec2780..64bbc1e 100644 --- a/src/main/java/com/android/tools/r8/code/Format4rcc.java +++ b/src/main/java/com/android/tools/r8/code/Format4rcc.java
@@ -7,8 +7,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.code.Invoke.Type; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; import java.util.function.BiPredicate; @@ -40,11 +45,21 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC); + assert lookup.getType() == Type.POLYMORPHIC; writeFirst(AA, dest); - write16BitReference(BBBB, dest, mapping); + write16BitReference(lookup.getMethod(), dest, mapping); write16BitValue(CCCC, dest); - write16BitReference(HHHH, dest, mapping); + + DexProto rewrittenProto = rewriter.rewriteProto(getProto()); + write16BitReference(rewrittenProto, dest, mapping); } @Override @@ -93,9 +108,18 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - BBBB.collectIndexedItems(indexedItems); - HHHH.collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC); + assert lookup.getType() == Type.POLYMORPHIC; + lookup.getMethod().collectIndexedItems(indexedItems); + + DexProto rewrittenProto = rewriter.rewriteProto(getProto()); + rewrittenProto.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/Format51l.java b/src/main/java/com/android/tools/r8/code/Format51l.java index 0e9ad93..face456 100644 --- a/src/main/java/com/android/tools/r8/code/Format51l.java +++ b/src/main/java/com/android/tools/r8/code/Format51l.java
@@ -5,7 +5,10 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -28,7 +31,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(AA, dest); write64BitValue(BBBBBBBBBBBBBBBB, dest); } @@ -53,7 +61,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/IgetOrIput.java b/src/main/java/com/android/tools/r8/code/IgetOrIput.java index 7800ace..33621e5 100644 --- a/src/main/java/com/android/tools/r8/code/IgetOrIput.java +++ b/src/main/java/com/android/tools/r8/code/IgetOrIput.java
@@ -5,6 +5,11 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public abstract class IgetOrIput extends Format22c<DexField> { @@ -17,12 +22,29 @@ } @Override - public final void collectIndexedItems(IndexedItemCollection indexedItems) { - getField().collectIndexedItems(indexedItems); + public final void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexField rewritten = graphLens.lookupField(getField()); + rewritten.collectIndexedItems(indexedItems); } @Override public final DexField getField() { return CCCC; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexField lookup = graphLens.lookupField(getField()); + writeFirst(B, A, dest); + write16BitReference(lookup, dest, mapping); + } }
diff --git a/src/main/java/com/android/tools/r8/code/InstanceOf.java b/src/main/java/com/android/tools/r8/code/InstanceOf.java index 05a9558..6c9d960 100644 --- a/src/main/java/com/android/tools/r8/code/InstanceOf.java +++ b/src/main/java/com/android/tools/r8/code/InstanceOf.java
@@ -5,9 +5,14 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public class InstanceOf extends Format22c<DexType> { @@ -49,8 +54,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } public DexType getType() { @@ -71,4 +81,16 @@ public boolean canThrow() { return true; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexType lookup = graphLens.lookupType(getType()); + writeFirst(B, A, dest); + write16BitReference(lookup, dest, mapping); + } }
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java index d8accd7..766638c 100644 --- a/src/main/java/com/android/tools/r8/code/Instruction.java +++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -9,10 +9,13 @@ import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -90,7 +93,11 @@ } protected void writeFirst(int a, int b, ShortBuffer dest) { - dest.put((short) (((a & 0xf) << 12) | ((b & 0xf) << 8) | (getOpcode() & 0xff))); + writeFirst(a, b, dest, getOpcode()); + } + + protected void writeFirst(int a, int b, ShortBuffer dest, int opcode) { + dest.put((short) (((a & 0xf) << 12) | ((b & 0xf) << 8) | (opcode & 0xff))); } protected void write16BitValue(int value, ShortBuffer dest) { @@ -107,8 +114,8 @@ write32BitValue((value >> 32) & 0xffffffff, dest); } - protected void write16BitReference(IndexedDexItem item, ShortBuffer dest, - ObjectToOffsetMapping mapping) { + protected void write16BitReference( + IndexedDexItem item, ShortBuffer dest, ObjectToOffsetMapping mapping) { int index = item.getOffset(mapping); assert index == (index & 0xffff); write16BitValue(index, dest); @@ -309,9 +316,18 @@ return toString(null); } - public abstract void write(ShortBuffer buffer, ObjectToOffsetMapping mapping); + public abstract void write( + ShortBuffer buffer, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter); - public abstract void collectIndexedItems(IndexedItemCollection indexedItems); + public abstract void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter); public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) { // In the default case, there is nothing to substitute.
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/code/InvokeCustom.java index 72d0adb..1355f13 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeCustom.java +++ b/src/main/java/com/android/tools/r8/code/InvokeCustom.java
@@ -5,9 +5,14 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexCallSite; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public class InvokeCustom extends Format35c<DexCallSite> { @@ -39,8 +44,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getCallSite().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context); + rewritten.collectIndexedItems(indexedItems); } @Override @@ -62,4 +72,16 @@ public boolean canThrow() { return true; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + writeFirst(A, G, dest); + write16BitReference(rewriter.rewriteCallSite(getCallSite(), context), dest, mapping); + write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest); + } }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java index ae63c4d..2d09e4f 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
@@ -5,9 +5,14 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexCallSite; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public class InvokeCustomRange extends Format3rc<DexCallSite> { @@ -39,8 +44,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getCallSite().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context); + rewritten.collectIndexedItems(indexedItems); } @Override @@ -62,4 +72,17 @@ public boolean canThrow() { return true; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context); + writeFirst(AA, dest); + write16BitReference(rewritten, dest, mapping); + write16BitValue(CCCC, dest); + } }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/code/InvokeDirect.java index cd8c1b7..6786de8 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeDirect.java +++ b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.DIRECT; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java index 41070dd..843d968 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.DIRECT; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/code/InvokeInterface.java index 3e172e2..89b8a16 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeInterface.java +++ b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.INTERFACE; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java index 2d1986c..e710b8c 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.INTERFACE; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/code/InvokeMethod.java index cab1eac..c8539f3 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeMethod.java +++ b/src/main/java/com/android/tools/r8/code/InvokeMethod.java
@@ -5,6 +5,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; +import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.code.Invoke; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public abstract class InvokeMethod extends Format35c<DexMethod> { @@ -17,12 +24,34 @@ } @Override - public final void collectIndexedItems(IndexedItemCollection indexedItems) { - getMethod().collectIndexedItems(indexedItems); + public final void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexMethod rewritten = + graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()).getMethod(); + rewritten.collectIndexedItems(indexedItems); } @Override public final DexMethod getMethod() { return BBBB; } + + public abstract Invoke.Type getInvokeType(); + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()); + writeFirst(A, G, dest, lookup.getType().getDexOpcode()); + write16BitReference(lookup.getMethod(), dest, mapping); + write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest); + } }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java index 25fad42..4e4d705 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
@@ -5,6 +5,13 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; +import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.code.Invoke.Type; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public abstract class InvokeMethodRange extends Format3rc<DexMethod> { @@ -17,12 +24,34 @@ } @Override - public final void collectIndexedItems(IndexedItemCollection indexedItems) { - getMethod().collectIndexedItems(indexedItems); + public final void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexMethod rewritten = + graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()).getMethod(); + rewritten.collectIndexedItems(indexedItems); } @Override public final DexMethod getMethod() { return BBBB; } + + public abstract Type getInvokeType(); + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + GraphLensLookupResult lookup = + graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()); + writeFirst(AA, dest, lookup.getType().getDexOpcodeRange()); + write16BitReference(lookup.getMethod(), dest, mapping); + write16BitValue(CCCC, dest); + } }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/code/InvokeStatic.java index 531105b..796b183 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeStatic.java +++ b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.STATIC; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java index 7d3ff3d..20809c9 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.STATIC; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/code/InvokeSuper.java index 1dc8ac6..d2d6e28 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeSuper.java +++ b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.SUPER; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java index af6ebe8..70fd726 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.SUPER; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java index 17596a4..9b9e064 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java +++ b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.VIRTUAL; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java index c2a0d6c..a4f2e98 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
@@ -24,6 +24,11 @@ } @Override + public Type getInvokeType() { + return Type.VIRTUAL; + } + + @Override public String getName() { return NAME; }
diff --git a/src/main/java/com/android/tools/r8/code/NewArray.java b/src/main/java/com/android/tools/r8/code/NewArray.java index dfb4ccb..a0104a2 100644 --- a/src/main/java/com/android/tools/r8/code/NewArray.java +++ b/src/main/java/com/android/tools/r8/code/NewArray.java
@@ -5,9 +5,14 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; +import java.nio.ShortBuffer; public class NewArray extends Format22c<DexType> { @@ -39,8 +44,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } @Override @@ -61,4 +71,16 @@ public boolean canThrow() { return true; } + + @Override + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { + DexType lookup = graphLens.lookupType(getType()); + writeFirst(B, A, dest); + write16BitReference(lookup, dest, mapping); + } }
diff --git a/src/main/java/com/android/tools/r8/code/NewInstance.java b/src/main/java/com/android/tools/r8/code/NewInstance.java index 695ae96..da58744 100644 --- a/src/main/java/com/android/tools/r8/code/NewInstance.java +++ b/src/main/java/com/android/tools/r8/code/NewInstance.java
@@ -5,9 +5,12 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.OffsetToObjectMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; public class NewInstance extends Format21c<DexType> { @@ -39,8 +42,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems) { - getType().collectIndexedItems(indexedItems); + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexType rewritten = graphLens.lookupType(getType()); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java b/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java index 110f668..c7caf43 100644 --- a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java +++ b/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
@@ -3,7 +3,10 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -38,7 +41,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(1, dest); // Pseudo-opcode = 0x0100 write16BitValue(size, dest); write32BitValue(first_key, dest);
diff --git a/src/main/java/com/android/tools/r8/code/SgetOrSput.java b/src/main/java/com/android/tools/r8/code/SgetOrSput.java index d04e098..1f77122 100644 --- a/src/main/java/com/android/tools/r8/code/SgetOrSput.java +++ b/src/main/java/com/android/tools/r8/code/SgetOrSput.java
@@ -5,6 +5,9 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; abstract class SgetOrSput extends Format21c<DexField> { @@ -17,8 +20,13 @@ } @Override - public final void collectIndexedItems(IndexedItemCollection indexedItems) { - getField().collectIndexedItems(indexedItems); + public final void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { + DexField rewritten = graphLens.lookupField(getField()); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java b/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java index 90b88cc..b73779b 100644 --- a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java +++ b/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
@@ -3,7 +3,10 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; import java.nio.ShortBuffer; @@ -42,7 +45,12 @@ } @Override - public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { + public void write( + ShortBuffer dest, + ProgramMethod context, + GraphLens graphLens, + ObjectToOffsetMapping mapping, + LensCodeRewriterUtils rewriter) { writeFirst(2, dest); // Pseudo-opcode = 0x0200 write16BitValue(size, dest); for (int i = 0; i < size; i++) {
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java index 5190adb..6b0d055 100644 --- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java +++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -24,10 +24,12 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexLibraryClass; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.JarApplicationReader; import com.android.tools.r8.graph.JarClassFileReader; import com.android.tools.r8.graph.LazyLoadedDexApplication; import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.ClassProvider; @@ -36,7 +38,7 @@ import com.android.tools.r8.utils.DexVersion; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.LibraryClassCollection; -import com.android.tools.r8.utils.MainDexList; +import com.android.tools.r8.utils.MainDexListParser; import com.android.tools.r8.utils.ProgramClassCollection; import com.android.tools.r8.utils.StringDiagnostic; import com.android.tools.r8.utils.ThreadUtils; @@ -78,7 +80,9 @@ return read((StringResource) null); } - public LazyLoadedDexApplication read(StringResource proguardMap) throws IOException { + public LazyLoadedDexApplication read( + StringResource proguardMap) + throws IOException { ExecutorService executor = Executors.newSingleThreadExecutor(); try { return read(proguardMap, executor); @@ -87,7 +91,9 @@ } } - public final LazyLoadedDexApplication read(ExecutorService executorService) throws IOException { + public final LazyLoadedDexApplication read( + ExecutorService executorService) + throws IOException { return read( inputApp.getProguardMapInputData(), executorService, @@ -95,7 +101,9 @@ } public final LazyLoadedDexApplication read( - StringResource proguardMap, ExecutorService executorService) throws IOException { + StringResource proguardMap, + ExecutorService executorService) + throws IOException { return read( proguardMap, executorService, @@ -146,7 +154,6 @@ // about class descriptor. // TODO: try and preload less classes. readProguardMap(proguardMap, builder, executorService, futures); - readMainDexList(builder, executorService, futures); ClassReader classReader = new ClassReader(executorService, futures); JarClassFileReader jcf = classReader.readSources(); ThreadUtils.awaitFutures(futures); @@ -167,6 +174,38 @@ return builder.build(); } + public MainDexClasses readMainDexClasses(DexApplication app) { + MainDexClasses.Builder builder = MainDexClasses.builder(); + if (inputApp.hasMainDexList()) { + for (StringResource resource : inputApp.getMainDexListResources()) { + addToMainDexClasses(app, builder, MainDexListParser.parseList(resource, itemFactory)); + } + addToMainDexClasses( + app, + builder, + inputApp.getMainDexClasses().stream() + .map(clazz -> itemFactory.createType(DescriptorUtils.javaTypeToDescriptor(clazz))) + .collect(Collectors.toList())); + } + return builder.build(); + } + + private void addToMainDexClasses( + DexApplication app, MainDexClasses.Builder builder, Iterable<DexType> types) { + for (DexType type : types) { + DexProgramClass clazz = app.programDefinitionFor(type); + if (clazz != null) { + builder.add(clazz); + } else if (!options.ignoreMainDexMissingClasses) { + options.reporter.warning( + new StringDiagnostic( + "Application does not contain `" + + type.toSourceString() + + "` as referenced in main-dex-list.")); + } + } + } + private static void dumpInputToFile(AndroidApp app, Path output, InternalOptions options) { app.dump(output, options); } @@ -220,23 +259,6 @@ })); } - private void readMainDexList(DexApplication.Builder<?> builder, ExecutorService executorService, - List<Future<?>> futures) { - if (inputApp.hasMainDexList()) { - futures.add(executorService.submit(() -> { - for (StringResource resource : inputApp.getMainDexListResources()) { - builder.addToMainDexList(MainDexList.parseList(resource, itemFactory)); - } - - builder.addToMainDexList( - inputApp.getMainDexClasses() - .stream() - .map(clazz -> itemFactory.createType(DescriptorUtils.javaTypeToDescriptor(clazz))) - .collect(Collectors.toList())); - })); - } - } - private final class ClassReader { private final ExecutorService executorService; private final List<Future<?>> futures;
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java index 21b5cd4..b0f836c 100644 --- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -44,6 +44,7 @@ import com.android.tools.r8.naming.ProguardMapSupplier; import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId; import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.ExceptionUtils; import com.android.tools.r8.utils.InternalOptions; @@ -69,7 +70,6 @@ public class ApplicationWriter { - public final DexApplication application; public final AppView<?> appView; public final GraphLens graphLens; public final InitClassLens initClassLens; @@ -146,18 +146,14 @@ } public ApplicationWriter( - DexApplication application, AppView<?> appView, - InternalOptions options, List<Marker> markers, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, ProguardMapSupplier proguardMapSupplier) { this( - application, appView, - options, markers, graphLens, initClassLens, @@ -167,20 +163,15 @@ } public ApplicationWriter( - DexApplication application, AppView<?> appView, - InternalOptions options, List<Marker> markers, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, ProguardMapSupplier proguardMapSupplier, DexIndexedConsumer consumer) { - assert application != null; - this.application = application; this.appView = appView; - assert options != null; - this.options = options; + this.options = appView.options(); this.desugaredLibraryCodeToKeep = CodeToKeep.createCodeToKeep(options, namingLens); this.markers = markers; this.graphLens = graphLens; @@ -199,7 +190,7 @@ options.getDexFilePerClassFileConsumer().combineSyntheticClassesWithPrimaryClass()); } else if (!options.canUseMultidex() && options.mainDexKeepRules.isEmpty() - && application.mainDexList.isEmpty() + && appView.appInfo().getMainDexClasses().isEmpty() && options.enableMainDexListCheck) { distributor = new VirtualFile.MonoDexDistributor(this, options); } else { @@ -215,7 +206,7 @@ * This needs to be done after distribute but before dex string sorting. */ private void encodeChecksums(Iterable<VirtualFile> files) { - List<DexProgramClass> classes = application.classes(); + Collection<DexProgramClass> classes = appView.appInfo().classes(); Reference2LongMap<DexString> inputChecksums = new Reference2LongOpenHashMap<>(classes.size()); for (DexProgramClass clazz : classes) { inputChecksums.put(clazz.getType().descriptor, clazz.getChecksum()); @@ -226,12 +217,12 @@ DexString desc = clazz.type.descriptor; toWrite.addChecksum(desc.toString(), inputChecksums.getLong(desc)); } - file.injectString(application.dexItemFactory.createString(toWrite.toJsonString())); + file.injectString(appView.dexItemFactory().createString(toWrite.toJsonString())); } } public void write(ExecutorService executorService) throws IOException, ExecutionException { - application.timing.begin("DexApplication.write"); + appView.appInfo().app().timing.begin("DexApplication.write"); ProguardMapId proguardMapId = null; if (proguardMapSupplier != null && options.proguardMapConsumer != null) { proguardMapId = proguardMapSupplier.writeProguardMap(); @@ -246,7 +237,7 @@ } markerStrings = new ArrayList<>(markers.size()); for (Marker marker : markers) { - markerStrings.add(application.dexItemFactory.createString(marker.toString())); + markerStrings.add(appView.dexItemFactory().createString(marker.toString())); } } try { @@ -266,16 +257,14 @@ } assert markers == null || markers.isEmpty() - || application.dexItemFactory.extractMarkers() != null; - assert appView == null - || appView.withProtoShrinker( - shrinker -> - virtualFiles.stream().allMatch(shrinker::verifyDeadProtoTypesNotReferenced), - true); + || appView.dexItemFactory().extractMarkers() != null; + assert appView.withProtoShrinker( + shrinker -> virtualFiles.stream().allMatch(shrinker::verifyDeadProtoTypesNotReferenced), + true); // TODO(b/151313617): Sorting annotations mutates elements so run single threaded on main. SortAnnotations sortAnnotations = new SortAnnotations(namingLens); - application.classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations)); + appView.appInfo().classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations)); for (VirtualFile virtualFile : virtualFiles) { if (virtualFile.isEmpty()) { @@ -305,10 +294,11 @@ } } ObjectToOffsetMapping objectMapping = - virtualFile.computeMapping(application, namingLens, initClassLens); + virtualFile.computeMapping( + appView.appInfo(), graphLens, namingLens, initClassLens); MethodToCodeObjectMapping codeMapping = rewriteCodeWithJumboStrings( - objectMapping, virtualFile.classes(), application); + objectMapping, virtualFile.classes(), appView.appInfo().app()); ByteBufferResult result = writeDexFile(objectMapping, codeMapping, byteBufferProvider); ByteDataView data = @@ -345,9 +335,9 @@ // Fail if there are pending errors, e.g., the program consumers may have reported errors. options.reporter.failIfPendingErrors(); // Supply info to all additional resource consumers. - supplyAdditionalConsumers(application, appView, graphLens, namingLens, options); + supplyAdditionalConsumers(appView.appInfo().app(), appView, graphLens, namingLens, options); } finally { - application.timing.end(); + appView.appInfo().app().timing.end(); } } @@ -365,7 +355,7 @@ } if (options.mainDexListConsumer != null) { ExceptionUtils.withConsumeResourceHandler( - options.reporter, options.mainDexListConsumer, writeMainDexList(application, namingLens)); + options.reporter, options.mainDexListConsumer, writeMainDexList(appView, namingLens)); ExceptionUtils.withFinishedResourceHandler(options.reporter, options.mainDexListConsumer); } @@ -461,7 +451,7 @@ private void insertAttributeAnnotations() { // Convert inner-class attributes to DEX annotations - for (DexProgramClass clazz : application.classes()) { + for (DexProgramClass clazz : appView.appInfo().classes()) { EnclosingMethodAttribute enclosingMethod = clazz.getEnclosingMethodAttribute(); List<InnerClassAttribute> innerClasses = clazz.getInnerClasses(); if (enclosingMethod == null && innerClasses.isEmpty()) { @@ -609,7 +599,7 @@ provider, objectMapping, codeMapping, - application, + appView.appInfo().app(), options, namingLens, desugaredLibraryCodeToKeep); @@ -624,9 +614,11 @@ .replace('.', '/') + ".class"; } - private static String writeMainDexList(DexApplication application, NamingLens namingLens) { + private static String writeMainDexList(AppView<?> appView, NamingLens namingLens) { + MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses(); StringBuilder builder = new StringBuilder(); - List<DexType> list = new ArrayList<>(application.mainDexList); + List<DexType> list = new ArrayList<>(mainDexClasses.size()); + mainDexClasses.forEach(list::add); list.sort(DexType::slowCompareTo); list.forEach( type -> builder.append(mapMainDexListName(type, namingLens)).append('\n'));
diff --git a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java index 037d769..b193e73 100644 --- a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java +++ b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
@@ -6,9 +6,11 @@ import com.android.tools.r8.ByteBufferProvider; import com.android.tools.r8.code.Instruction; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.graph.DexCode; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.utils.EncodedValueUtils; import com.android.tools.r8.utils.LebUtils; import com.google.common.annotations.VisibleForTesting; @@ -93,16 +95,20 @@ } public void putInstructions( - Instruction[] insns, ObjectToOffsetMapping mapping, CodeToKeep desugaredLibraryCodeToKeep) { + DexCode code, + ProgramMethod context, + ObjectToOffsetMapping mapping, + CodeToKeep desugaredLibraryCodeToKeep) { int size = 0; - for (Instruction insn : insns) { - size += insn.getSize(); + Instruction[] instructions = code.instructions; + for (Instruction instruction : instructions) { + size += instruction.getSize(); } ensureSpaceFor(size * Short.BYTES); assert byteBuffer.position() % 2 == 0; ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); - for (int i = 0; i < insns.length; i++) { - Instruction insn = insns[i]; + for (int i = 0; i < instructions.length; i++) { + Instruction insn = instructions[i]; DexMethod method = insn.getMethod(); DexField field = insn.getField(); if (field != null) { @@ -117,7 +123,8 @@ } else if (insn.isCheckCast()) { desugaredLibraryCodeToKeep.recordClass(insn.asCheckCast().getType()); } - insn.write(shortBuffer, mapping); + insn.write( + shortBuffer, context, mapping.getGraphLens(), mapping, mapping.getLensCodeRewriter()); } byteBuffer.position(byteBuffer.position() + shortBuffer.position() * Short.BYTES); }
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java index da90a09..393297a 100644 --- a/src/main/java/com/android/tools/r8/dex/FileWriter.java +++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -46,6 +46,8 @@ import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.graph.ProgramClassVisitor; +import com.android.tools.r8.graph.ProgramDexCode; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.logging.Log; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.MemberNaming.MethodSignature; @@ -175,7 +177,7 @@ assert codeMapping.verifyCodeObjects(mixedSectionOffsets.getCodes()); // Sort the codes first, as their order might impact size due to alignment constraints. - List<DexCode> codes = sortDexCodesByClassName(); + List<ProgramDexCode> codes = sortDexCodesByClassName(); // Output the debug_info_items first, as they have no dependencies. dest.moveTo(layout.getCodesOffset() + sizeOfCodeItems(codes)); @@ -185,8 +187,8 @@ // Ensure deterministic ordering of debug info by sorting consistent with the code objects. layout.setDebugInfosOffset(dest.align(1)); Set<DexDebugInfo> seen = new HashSet<>(mixedSectionOffsets.getDebugInfos().size()); - for (DexCode code : codes) { - DexDebugInfoForWriting info = code.getDebugInfoForWriting(); + for (ProgramDexCode code : codes) { + DexDebugInfoForWriting info = code.getCode().getDebugInfoForWriting(); if (info != null && seen.add(info)) { writeDebugItem(info); } @@ -323,18 +325,19 @@ return true; } - private List<DexCode> sortDexCodesByClassName() { - Map<DexCode, String> codeToSignatureMap = new IdentityHashMap<>(); - List<DexCode> codesSorted = new ArrayList<>(); + private List<ProgramDexCode> sortDexCodesByClassName() { + Map<ProgramDexCode, String> codeToSignatureMap = new IdentityHashMap<>(); + List<ProgramDexCode> codesSorted = new ArrayList<>(); for (DexProgramClass clazz : mapping.getClasses()) { - clazz.forEachMethod( + clazz.forEachProgramMethod( method -> { - DexCode code = codeMapping.getCode(method); - assert code != null || method.shouldNotHaveCode(); + DexCode code = codeMapping.getCode(method.getDefinition()); + assert code != null || method.getDefinition().shouldNotHaveCode(); if (code != null) { - codesSorted.add(code); - addSignaturesFromMethod( - method, code, codeToSignatureMap, application.getProguardMap()); + ProgramDexCode programCode = new ProgramDexCode(code, method); + codesSorted.add(programCode); + codeToSignatureMap.put( + programCode, getKeyForDexCodeSorting(method, application.getProguardMap())); } }); } @@ -342,21 +345,17 @@ return codesSorted; } - private static void addSignaturesFromMethod( - DexEncodedMethod method, - DexCode code, - Map<DexCode, String> codeToSignatureMap, - ClassNameMapper proguardMap) { + private static String getKeyForDexCodeSorting(ProgramMethod method, ClassNameMapper proguardMap) { Signature signature; String originalClassName; if (proguardMap != null) { - signature = proguardMap.originalSignatureOf(method.method); - originalClassName = proguardMap.originalNameOf(method.holder()); + signature = proguardMap.originalSignatureOf(method.getReference()); + originalClassName = proguardMap.originalNameOf(method.getHolderType()); } else { - signature = MethodSignature.fromDexMethod(method.method); - originalClassName = method.holder().toSourceString(); + signature = MethodSignature.fromDexMethod(method.getReference()); + originalClassName = method.getHolderType().toSourceString(); } - codeToSignatureMap.put(code, originalClassName + signature); + return originalClassName + signature; } private <T extends IndexedDexItem> void writeFixedSectionItems( @@ -380,8 +379,8 @@ writeItems(items, offsetSetter, writer, 1); } - private <T extends DexItem> void writeItems(Collection<T> items, Consumer<Integer> offsetSetter, - Consumer<T> writer, int alignment) { + private <T> void writeItems( + Collection<T> items, Consumer<Integer> offsetSetter, Consumer<T> writer, int alignment) { if (items.isEmpty()) { offsetSetter.accept(0); } else { @@ -390,11 +389,11 @@ } } - private int sizeOfCodeItems(Iterable<DexCode> codes) { + private int sizeOfCodeItems(Iterable<ProgramDexCode> codes) { int size = 0; - for (DexCode code : codes) { + for (ProgramDexCode code : codes) { size = alignSize(4, size); - size += sizeOfCodeItem(code); + size += sizeOfCodeItem(code.getCode()); } return size; } @@ -488,7 +487,11 @@ dest.putBytes(new DebugBytecodeWriter(debugInfo, mapping).generate()); } - private void writeCodeItem(DexCode code) { + private void writeCodeItem(ProgramDexCode code) { + writeCodeItem(code.getCode(), code.getMethod()); + } + + private void writeCodeItem(DexCode code, ProgramMethod method) { mixedSectionOffsets.setOffsetFor(code, dest.align(4)); // Fixed size header information. dest.putShort((short) code.registerSize); @@ -500,7 +503,7 @@ int insnSizeOffset = dest.position(); dest.forward(4); // Write instruction stream. - dest.putInstructions(code.instructions, mapping, desugaredLibraryCodeToKeep); + dest.putInstructions(code, method, mapping, desugaredLibraryCodeToKeep); // Compute size and do the backward/forward dance to write the size at the beginning. int insnSize = dest.position() - insnSizeOffset - 4; dest.rewind(insnSize + 4);
diff --git a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java index 709eb9d..3a88e5d 100644 --- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java +++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -6,7 +6,7 @@ import com.android.tools.r8.dex.VirtualFile.VirtualFileCycler; import com.android.tools.r8.errors.CompilationError; -import com.android.tools.r8.graph.DexApplication; +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; @@ -71,7 +71,7 @@ public void updateNumbersOfIds() { // Use a temporary VirtualFile to evaluate the number of ids in the group. - VirtualFile virtualFile = new VirtualFile(0, graphLens, initClassLens, namingLens); + VirtualFile virtualFile = new VirtualFile(0, appView, graphLens, initClassLens, namingLens); // Note: sort not needed. for (DexProgramClass clazz : members) { virtualFile.addClass(clazz); @@ -158,29 +158,30 @@ } - private boolean isDependingOnMainDexClass(Set<DexProgramClass> mainDexDependents, - DexProgramClass dexProgramClass) { - if (dexProgramClass == null) { + private boolean isDependingOnMainDexClass( + Set<DexProgramClass> mainDexDependents, DexProgramClass clazz) { + if (clazz == null) { return false; } // Think: build on one Map<dexProgramClass, Boolean> and split in a second step. - if (mainDexIndependents.contains(dexProgramClass)) { + if (mainDexIndependents.contains(clazz)) { return false; } - if (mainDexDependents.contains(dexProgramClass)) { + if (mainDexDependents.contains(clazz)) { return true; } - if (mainDex.classes().contains(dexProgramClass)) { + if (mainDex.classes().contains(clazz)) { return true; } boolean isDependent = false; - if (isDependingOnMainDexClass(mainDexDependents, - app.programDefinitionFor(dexProgramClass.superType))) { + if (isDependingOnMainDexClass( + mainDexDependents, appView.programDefinitionFor(clazz.superType, clazz))) { isDependent = true; } else { - for (DexType interfaze : dexProgramClass.interfaces.values) { - if (isDependingOnMainDexClass(mainDexDependents, app.programDefinitionFor(interfaze))) { + for (DexType interfaze : clazz.interfaces.values) { + if (isDependingOnMainDexClass( + mainDexDependents, appView.programDefinitionFor(interfaze, clazz))) { isDependent = true; break; } @@ -188,38 +189,37 @@ } if (isDependent) { - mainDexDependents.add(dexProgramClass); + mainDexDependents.add(clazz); } else { - mainDexIndependents.add(dexProgramClass); + mainDexIndependents.add(clazz); } return isDependent; } - - private boolean isDependingOnMainDexIndependents(DexProgramClass dexProgramClass) { - if (dexProgramClass == null) { + private boolean isDependingOnMainDexIndependents(DexProgramClass clazz) { + if (clazz == null) { return false; } // Think: build on one Map<dexProgramClass, Boolean> and split in a second step. - if (independentsFromMainDexIndependents.contains(dexProgramClass)) { + if (independentsFromMainDexIndependents.contains(clazz)) { return false; } - if (dependentsOfMainDexIndependents.contains(dexProgramClass)) { + if (dependentsOfMainDexIndependents.contains(clazz)) { return true; } - if (mainDex.classes().contains(dexProgramClass)) { + if (mainDex.classes().contains(clazz)) { return false; } - if (mainDexIndependents.contains(dexProgramClass)) { + if (mainDexIndependents.contains(clazz)) { return true; } boolean isDependent = false; - if (isDependingOnMainDexIndependents(app.programDefinitionFor(dexProgramClass.superType))) { + if (isDependingOnMainDexIndependents(appView.programDefinitionFor(clazz.superType, clazz))) { isDependent = true; } else { - for (DexType interfaze : dexProgramClass.interfaces.values) { - if (isDependingOnMainDexIndependents(app.programDefinitionFor(interfaze))) { + for (DexType interfaze : clazz.interfaces.values) { + if (isDependingOnMainDexIndependents(appView.programDefinitionFor(interfaze, clazz))) { isDependent = true; break; } @@ -227,9 +227,9 @@ } if (isDependent) { - dependentsOfMainDexIndependents.add(dexProgramClass); + dependentsOfMainDexIndependents.add(clazz); } else { - independentsFromMainDexIndependents.add(dexProgramClass); + independentsFromMainDexIndependents.add(clazz); } return isDependent; } @@ -245,12 +245,12 @@ private final Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses; private final Set<DexProgramClass> classes; - DirectSubClassesInfo(DexApplication app, Set<DexProgramClass> classes) { + DirectSubClassesInfo(AppView<?> appView, Set<DexProgramClass> classes) { Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses = new HashMap<>(); for (DexProgramClass clazz : classes) { - addDirectSubClass(app, classes, directSubClasses, clazz.superType, clazz); + addDirectSubClass(appView, classes, directSubClasses, clazz.superType, clazz); for (DexType interfaze : clazz.interfaces.values) { - addDirectSubClass(app, classes, directSubClasses, interfaze, clazz); + addDirectSubClass(appView, classes, directSubClasses, interfaze, clazz); } } @@ -263,12 +263,13 @@ return directSubClasses.getOrDefault(clazz, Collections.emptyList()); } - private static void addDirectSubClass(DexApplication app, + private static void addDirectSubClass( + AppView<?> appView, Set<DexProgramClass> classes, Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses, DexType superType, DexProgramClass clazz) { - DexProgramClass zuper = app.programDefinitionFor(superType); + DexProgramClass zuper = appView.programDefinitionFor(superType, clazz); // Don't bother collecting subclasses info that we won't use. if (zuper != null && classes.contains(zuper)) { Collection<DexProgramClass> subClasses = @@ -283,7 +284,7 @@ private final List<VirtualFile> dexes; private final BitSet fullDex = new BitSet(); private final Set<DexProgramClass> classes; - private final DexApplication app; + private final AppView<?> appView; private int dexIndexOffset; private final GraphLens graphLens; private final InitClassLens initClassLens; @@ -298,7 +299,7 @@ GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, - DexApplication app, + AppView<?> appView, ExecutorService executorService) { this.mainDex = mainDex; this.dexes = dexes; @@ -307,10 +308,10 @@ this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; - this.app = app; + this.appView = appView; this.executorService = executorService; - directSubClasses = new DirectSubClassesInfo(app, classes); + directSubClasses = new DirectSubClassesInfo(appView, classes); } public void distribute() { @@ -378,7 +379,7 @@ private Collection<VirtualFile> assignGroup(ClassGroup group, List<VirtualFile> dexBlackList) { VirtualFileCycler cycler = - new VirtualFileCycler(dexes, graphLens, initClassLens, namingLens, dexIndexOffset); + new VirtualFileCycler(dexes, appView, graphLens, initClassLens, namingLens, dexIndexOffset); if (group.members.isEmpty()) { return Collections.emptyList(); } else if (group.canFitInOneDex()) { @@ -427,7 +428,7 @@ Collection<VirtualFile> usedDex = new ArrayList<>(); VirtualFileCycler cycler = - new VirtualFileCycler(dexes, graphLens, initClassLens, namingLens, dexIndexOffset); + new VirtualFileCycler(dexes, appView, graphLens, initClassLens, namingLens, dexIndexOffset); // Don't modify input dexBlackList. Think about modifying the input collection considering this // is private API. Set<VirtualFile> currentBlackList = new HashSet<>(dexBlackList); @@ -581,9 +582,9 @@ group.members.add(clazz); // Check dependencies are added to the group. - collectGroup(classes, group, app.programDefinitionFor(clazz.superType)); + collectGroup(classes, group, appView.programDefinitionFor(clazz.superType, clazz)); for (DexType interfaze : clazz.interfaces.values) { - collectGroup(classes, group, app.programDefinitionFor(interfaze)); + collectGroup(classes, group, appView.programDefinitionFor(interfaze, clazz)); } // Check that dependants are added to the group. @@ -666,11 +667,11 @@ private boolean hasDirectInheritanceInCollection(DexProgramClass clazz, Set<DexProgramClass> collection) { - if (collection.contains(app.programDefinitionFor(clazz.superType))) { + if (collection.contains(appView.programDefinitionFor(clazz.superType, clazz))) { return true; } for (DexType interfaze : clazz.interfaces.values) { - if (collection.contains(app.programDefinitionFor(interfaze))) { + if (collection.contains(appView.programDefinitionFor(interfaze, clazz))) { return true; } } @@ -708,13 +709,13 @@ private DexProgramClass findOneRootInSetFrom(DexProgramClass searchFrom, Set<DexProgramClass> classSet) { - DexProgramClass zuper = app.programDefinitionFor(searchFrom.superType); + DexProgramClass zuper = appView.programDefinitionFor(searchFrom.superType, searchFrom); if (classSet.contains(zuper)) { return findOneRootInSetFrom(zuper, classSet); } for (DexType interfaceType : searchFrom.interfaces.values) { - DexClass interfaceClass = app.definitionFor(interfaceType); - if (classSet.contains(interfaceClass)) { + DexClass interfaceClass = appView.definitionFor(interfaceType); + if (interfaceClass.isProgramClass() && classSet.contains(interfaceClass.asProgramClass())) { return findOneRootInSetFrom((DexProgramClass) interfaceClass, classSet); } }
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java index b036d96..5e31d99 100644 --- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java +++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -3,12 +3,14 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.dex; +import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; + import com.android.tools.r8.FeatureSplit; import com.android.tools.r8.errors.DexFileOverflowDiagnostic; import com.android.tools.r8.errors.InternalCompilerError; -import com.android.tools.r8.graph.DexApplication; +import com.android.tools.r8.graph.AppInfo; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexCallSite; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItem; import com.android.tools.r8.graph.DexItemFactory; @@ -21,14 +23,15 @@ import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.logging.Log; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.NamingLens; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.FileUtils; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Reporter; -import com.android.tools.r8.utils.StringDiagnostic; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; @@ -77,30 +80,38 @@ private final DexProgramClass primaryClass; - VirtualFile(int id, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens) { - this(id, graphLens, initClassLens, namingLens, null, null); + VirtualFile( + int id, + AppView<?> appView, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens) { + this(id, appView, graphLens, initClassLens, namingLens, null, null); } VirtualFile( int id, + AppView<?> appView, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, FeatureSplit featureSplit) { - this(id, graphLens, initClassLens, namingLens, null, featureSplit); + this(id, appView, graphLens, initClassLens, namingLens, null, featureSplit); } private VirtualFile( int id, + AppView<?> appView, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, DexProgramClass primaryClass) { - this(id, graphLens, initClassLens, namingLens, primaryClass, null); + this(id, appView, graphLens, initClassLens, namingLens, primaryClass, null); } private VirtualFile( int id, + AppView<?> appView, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, @@ -109,7 +120,7 @@ this.id = id; this.indexedItems = new VirtualFileIndexedItemCollection(graphLens, initClassLens, namingLens); this.transaction = - new IndexedItemTransaction(indexedItems, graphLens, initClassLens, namingLens); + new IndexedItemTransaction(indexedItems, appView, graphLens, initClassLens, namingLens); this.primaryClass = primaryClass; this.featureSplit = featureSplit; } @@ -193,10 +204,11 @@ } public ObjectToOffsetMapping computeMapping( - DexApplication application, NamingLens namingLens, InitClassLens initClassLens) { + AppInfo appInfo, GraphLens graphLens, NamingLens namingLens, InitClassLens initClassLens) { assert transaction.isEmpty(); return new ObjectToOffsetMapping( - application, + appInfo, + graphLens, namingLens, initClassLens, indexedItems.classes, @@ -272,12 +284,12 @@ } public abstract static class Distributor { - protected final DexApplication application; + protected final AppView<?> appView; protected final ApplicationWriter writer; protected final List<VirtualFile> virtualFiles = new ArrayList<>(); Distributor(ApplicationWriter writer) { - this.application = writer.application; + this.appView = writer.appView; this.writer = writer; } @@ -304,11 +316,12 @@ HashMap<DexProgramClass, VirtualFile> files = new HashMap<>(); Collection<DexProgramClass> synthetics = new ArrayList<>(); // Assign dedicated virtual files for all program classes. - for (DexProgramClass clazz : application.classes()) { + for (DexProgramClass clazz : appView.appInfo().classes()) { if (!combineSyntheticClassesWithPrimaryClass || clazz.getSynthesizedFrom().isEmpty()) { VirtualFile file = new VirtualFile( virtualFiles.size(), + writer.appView, writer.graphLens, writer.initClassLens, writer.namingLens, @@ -345,13 +358,15 @@ this.options = options; // Create the primary dex file. The distribution will add more if needed. - mainDexFile = new VirtualFile(0, writer.graphLens, writer.initClassLens, writer.namingLens); + mainDexFile = + new VirtualFile( + 0, writer.appView, writer.graphLens, writer.initClassLens, writer.namingLens); assert virtualFiles.isEmpty(); virtualFiles.add(mainDexFile); addMarkers(mainDexFile); - classes = Sets.newHashSet(application.classes()); - originalNames = computeOriginalNameMapping(classes, application.getProguardMap()); + classes = Sets.newHashSet(appView.appInfo().classes()); + originalNames = computeOriginalNameMapping(classes, appView.appInfo().app().getProguardMap()); } private void addMarkers(VirtualFile virtualFile) { @@ -364,37 +379,30 @@ } protected void fillForMainDexList(Set<DexProgramClass> classes) { - if (!application.mainDexList.isEmpty()) { - VirtualFile mainDexFile = virtualFiles.get(0); - for (DexType type : application.mainDexList) { - DexClass clazz = application.definitionFor(type); - if (clazz != null && clazz.isProgramClass()) { - DexProgramClass programClass = (DexProgramClass) clazz; - mainDexFile.addClass(programClass); - classes.remove(programClass); - } else { - if (!options.ignoreMainDexMissingClasses) { - options.reporter.warning( - new StringDiagnostic( - "Application does not contain `" - + type.toSourceString() - + "` as referenced in main-dex-list.")); - } - } - mainDexFile.commitTransaction(); - } - if (Log.ENABLED) { - Log.info( - VirtualFile.class, - "Main dex classes: " + mainDexFile.transaction.getNumberOfClasses()); - Log.info( - VirtualFile.class, - "Main dex methods: " + mainDexFile.transaction.getNumberOfMethods()); - Log.info( - VirtualFile.class, "Main dex fields: " + mainDexFile.transaction.getNumberOfFields()); - } - mainDexFile.throwIfFull(true, options.reporter); + MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses(); + if (mainDexClasses.isEmpty()) { + return; } + VirtualFile mainDexFile = virtualFiles.get(0); + mainDexClasses.forEach( + type -> { + DexProgramClass clazz = + asProgramClassOrNull(appView.appInfo().definitionForWithoutExistenceAssert(type)); + if (clazz != null) { + mainDexFile.addClass(clazz); + classes.remove(clazz); + } + mainDexFile.commitTransaction(); + }); + if (Log.ENABLED) { + Log.info( + VirtualFile.class, "Main dex classes: " + mainDexFile.transaction.getNumberOfClasses()); + Log.info( + VirtualFile.class, "Main dex methods: " + mainDexFile.transaction.getNumberOfMethods()); + Log.info( + VirtualFile.class, "Main dex fields: " + mainDexFile.transaction.getNumberOfFields()); + } + mainDexFile.throwIfFull(true, options.reporter); } TreeSet<DexProgramClass> sortClassesByPackage(Set<DexProgramClass> classes, @@ -437,7 +445,7 @@ // Pull out the classes that should go into feature splits. Map<FeatureSplit, Set<DexProgramClass>> featureSplitClasses = options.featureSplitConfiguration.getFeatureSplitClasses( - classes, application.getProguardMap()); + classes, appView.appInfo().app().getProguardMap()); if (featureSplitClasses.size() > 0) { for (Set<DexProgramClass> featureClasses : featureSplitClasses.values()) { classes.removeAll(featureClasses); @@ -464,6 +472,7 @@ VirtualFile featureFile = new VirtualFile( 0, + writer.appView, writer.graphLens, writer.initClassLens, writer.namingLens, @@ -476,9 +485,9 @@ new PackageSplitPopulator( filesForDistribution, + appView, featureClasses, originalNames, - application.dexItemFactory, fillStrategy, 0, writer.graphLens, @@ -519,7 +528,8 @@ assert virtualFiles.size() == 1; // The main dex file is filtered out, so ensure at least one file for the remaining classes. virtualFiles.add( - new VirtualFile(1, writer.graphLens, writer.initClassLens, writer.namingLens)); + new VirtualFile( + 1, writer.appView, writer.graphLens, writer.initClassLens, writer.namingLens)); filesForDistribution = virtualFiles.subList(1, virtualFiles.size()); fileIndexOffset = 1; } @@ -536,7 +546,7 @@ writer.graphLens, writer.initClassLens, writer.namingLens, - writer.application, + writer.appView, executorService) .distribute(); } else { @@ -545,9 +555,9 @@ classes = sortClassesByPackage(classes, originalNames); new PackageSplitPopulator( filesForDistribution, + appView, classes, originalNames, - application.dexItemFactory, fillStrategy, fileIndexOffset, writer.graphLens, @@ -695,6 +705,7 @@ private final GraphLens graphLens; private final InitClassLens initClassLens; private final NamingLens namingLens; + private final LensCodeRewriterUtils rewriter; private final Set<DexProgramClass> classes = new LinkedHashSet<>(); private final Set<DexField> fields = new LinkedHashSet<>(); @@ -707,6 +718,7 @@ private IndexedItemTransaction( VirtualFileIndexedItemCollection base, + AppView<?> appView, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens) { @@ -714,6 +726,7 @@ this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; + this.rewriter = new LensCodeRewriterUtils(appView, graphLens); } private <T extends DexItem> boolean maybeInsert(T item, Set<T> set, Set<T> baseSet) { @@ -725,7 +738,7 @@ } void addClassAndDependencies(DexProgramClass clazz) { - clazz.collectIndexedItems(this); + clazz.collectIndexedItems(this, graphLens, rewriter); } @Override @@ -855,6 +868,7 @@ static class VirtualFileCycler { private final List<VirtualFile> files; + private final AppView<?> appView; private final GraphLens graphLens; private final InitClassLens initClassLens; private final NamingLens namingLens; @@ -866,11 +880,13 @@ VirtualFileCycler( List<VirtualFile> files, + AppView<?> appView, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, int fileIndexOffset) { this.files = files; + this.appView = appView; this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; @@ -904,7 +920,8 @@ return activeFiles.next(); } else { VirtualFile newFile = - new VirtualFile(nextFileId++, graphLens, initClassLens, namingLens, featuresplit); + new VirtualFile( + nextFileId++, appView, graphLens, initClassLens, namingLens, featuresplit); files.add(newFile); allFilesCyclic = Iterators.cycle(files); return newFile; @@ -936,7 +953,8 @@ VirtualFile addFile() { VirtualFile newFile = - new VirtualFile(nextFileId++, graphLens, initClassLens, namingLens, featuresplit); + new VirtualFile( + nextFileId++, appView, graphLens, initClassLens, namingLens, featuresplit); files.add(newFile); reset(); @@ -977,9 +995,9 @@ PackageSplitPopulator( List<VirtualFile> files, + AppView<?> appView, Set<DexProgramClass> classes, Map<DexProgramClass, String> originalNames, - DexItemFactory dexItemFactory, FillStrategy fillStrategy, int fileIndexOffset, GraphLens graphLens, @@ -988,11 +1006,12 @@ InternalOptions options) { this.classes = new ArrayList<>(classes); this.originalNames = originalNames; - this.dexItemFactory = dexItemFactory; + this.dexItemFactory = appView.dexItemFactory(); this.fillStrategy = fillStrategy; this.options = options; this.cycler = - new VirtualFileCycler(files, graphLens, initClassLens, namingLens, fileIndexOffset); + new VirtualFileCycler( + files, appView, graphLens, initClassLens, namingLens, fileIndexOffset); } static boolean coveredByPrefix(String originalName, String currentPrefix) {
diff --git a/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java new file mode 100644 index 0000000..e078248 --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
@@ -0,0 +1,366 @@ +// 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.utils.collections.ProgramMethodSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * For a concrete field, stores the contexts in which the field is accessed. + * + * <p>If the concrete field does not have any accesses, then {@link EmptyAccessContexts}. + * + * <p>If nothing is nothing about the accesses to the concrete field, then {@link + * UnknownAccessContexts}. + * + * <p>Otherwise, the concrete contexts in which the field is accessed is maintained by {@link + * ConcreteAccessContexts}. The access contexts are qualified by the field reference they access. + * + * <p>Example: If a field `int Foo.field` is accessed directly in `void Main.direct()` and + * indirectly via a non-rebound reference `int FooSub.field` in `void Main.indirect()`, then the + * collection is: + * + * <pre> + * ConcreteAccessContexts { + * `int Foo.field` -> { `void Main.direct()` } + * `int FooSub.field` -> { `void Main.indirect()` } + * } + * </pre> + */ +public abstract class AbstractAccessContexts { + + abstract void flattenAccessContexts(DexField field); + + abstract void forEachAccessContext(Consumer<ProgramMethod> consumer); + + /** + * Returns true if this field is written by a method for which {@param predicate} returns true. + */ + abstract boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate); + + /** + * Returns true if this field is only written by methods for which {@param predicate} returns + * true. + */ + abstract boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate); + + /** + * Returns true if this field is written by a method in the program other than {@param method}. + */ + abstract boolean isAccessedOutside(DexEncodedMethod method); + + abstract int getNumberOfAccessContexts(); + + public boolean isBottom() { + return false; + } + + public boolean isConcrete() { + return false; + } + + abstract boolean isEmpty(); + + public ConcreteAccessContexts asConcrete() { + return null; + } + + public boolean isTop() { + return false; + } + + abstract AbstractAccessContexts rewrittenWithLens( + DexDefinitionSupplier definitions, GraphLens lens); + + public static EmptyAccessContexts empty() { + return EmptyAccessContexts.getInstance(); + } + + public static UnknownAccessContexts unknown() { + return UnknownAccessContexts.getInstance(); + } + + public static class EmptyAccessContexts extends AbstractAccessContexts { + + public static EmptyAccessContexts INSTANCE = new EmptyAccessContexts(); + + private EmptyAccessContexts() {} + + public static EmptyAccessContexts getInstance() { + return INSTANCE; + } + + @Override + void flattenAccessContexts(DexField field) { + // Intentionally empty. + } + + @Override + void forEachAccessContext(Consumer<ProgramMethod> consumer) { + // Intentionally empty. + } + + @Override + boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) { + return false; + } + + @Override + boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) { + return true; + } + + @Override + boolean isAccessedOutside(DexEncodedMethod method) { + return false; + } + + @Override + int getNumberOfAccessContexts() { + return 0; + } + + @Override + public boolean isBottom() { + return true; + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + AbstractAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) { + return this; + } + } + + public static class ConcreteAccessContexts extends AbstractAccessContexts { + + private final Map<DexField, ProgramMethodSet> accessesWithContexts; + + public ConcreteAccessContexts() { + this(new IdentityHashMap<>()); + } + + public ConcreteAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) { + this.accessesWithContexts = accessesWithContexts; + } + + void forEachAccess(Consumer<DexField> consumer, Predicate<DexField> predicate) { + if (accessesWithContexts != null) { + accessesWithContexts.forEach( + (access, contexts) -> { + if (predicate.test(access)) { + consumer.accept(access); + } + }); + } + } + + @Override + void forEachAccessContext(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. + ProgramMethodSet visited = ProgramMethodSet.create(); + if (accessesWithContexts != null) { + for (ProgramMethodSet encodedAccessContexts : accessesWithContexts.values()) { + for (ProgramMethod encodedAccessContext : encodedAccessContexts) { + if (visited.add(encodedAccessContext)) { + consumer.accept(encodedAccessContext); + } + } + } + } + } + + Map<DexField, ProgramMethodSet> getAccessesWithContexts() { + return accessesWithContexts; + } + + @Override + int getNumberOfAccessContexts() { + if (accessesWithContexts.size() == 1) { + return accessesWithContexts.values().iterator().next().size(); + } + throw new Unreachable( + "Should only be querying the number of access contexts after flattening"); + } + + ProgramMethod getUniqueAccessContext() { + if (accessesWithContexts != null && accessesWithContexts.size() == 1) { + ProgramMethodSet contexts = accessesWithContexts.values().iterator().next(); + if (contexts.size() == 1) { + return contexts.iterator().next(); + } + } + return null; + } + + @Override + void flattenAccessContexts(DexField field) { + if (accessesWithContexts != null) { + ProgramMethodSet flattenedAccessContexts = + accessesWithContexts.computeIfAbsent(field, ignore -> ProgramMethodSet.create()); + accessesWithContexts.forEach( + (access, contexts) -> { + if (access != field) { + flattenedAccessContexts.addAll(contexts); + } + }); + accessesWithContexts.clear(); + if (!flattenedAccessContexts.isEmpty()) { + accessesWithContexts.put(field, flattenedAccessContexts); + } + assert accessesWithContexts.size() <= 1; + } + } + + /** + * Returns true if this field is written by a method for which {@param predicate} returns true. + */ + @Override + public boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) { + for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) { + for (ProgramMethod encodedWriteContext : encodedWriteContexts) { + if (predicate.test(encodedWriteContext)) { + return true; + } + } + } + return false; + } + + /** + * Returns true if this field is only written by methods for which {@param predicate} returns + * true. + */ + @Override + public boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) { + for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) { + for (ProgramMethod encodedWriteContext : encodedWriteContexts) { + if (!predicate.test(encodedWriteContext)) { + return false; + } + } + } + return true; + } + + /** + * Returns true if this field is written by a method in the program other than {@param method}. + */ + @Override + public boolean isAccessedOutside(DexEncodedMethod method) { + for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) { + for (ProgramMethod encodedWriteContext : encodedWriteContexts) { + if (encodedWriteContext.getDefinition() != method) { + return true; + } + } + } + return false; + } + + @Override + public boolean isConcrete() { + return true; + } + + @Override + public ConcreteAccessContexts asConcrete() { + return this; + } + + @Override + public boolean isEmpty() { + return accessesWithContexts.isEmpty(); + } + + boolean recordAccess(DexField access, ProgramMethod context) { + return accessesWithContexts + .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) + .add(context); + } + + @Override + ConcreteAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) { + Map<DexField, ProgramMethodSet> newAccessesWithContexts = new IdentityHashMap<>(); + accessesWithContexts.forEach( + (access, contexts) -> { + ProgramMethodSet newContexts = + newAccessesWithContexts.computeIfAbsent( + lens.lookupField(access), ignore -> ProgramMethodSet.create()); + for (ProgramMethod context : contexts) { + newContexts.add(lens.mapProgramMethod(context, definitions)); + } + }); + return new ConcreteAccessContexts(newAccessesWithContexts); + } + } + + public static class UnknownAccessContexts extends AbstractAccessContexts { + + public static UnknownAccessContexts INSTANCE = new UnknownAccessContexts(); + + private UnknownAccessContexts() {} + + public static UnknownAccessContexts getInstance() { + return INSTANCE; + } + + @Override + void flattenAccessContexts(DexField field) { + // Intentionally empty. + } + + @Override + void forEachAccessContext(Consumer<ProgramMethod> consumer) { + throw new Unreachable("Should never be iterating the access contexts when they are unknown"); + } + + @Override + boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) { + return true; + } + + @Override + boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) { + return false; + } + + @Override + boolean isAccessedOutside(DexEncodedMethod method) { + return true; + } + + @Override + int getNumberOfAccessContexts() { + throw new Unreachable( + "Should never be querying the number of access contexts when they are unknown"); + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean isTop() { + return true; + } + + @Override + AbstractAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) { + return this; + } + } +}
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 59239db..c49eb28 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfo.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -8,6 +8,7 @@ import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.BooleanBox; import com.android.tools.r8.utils.InternalOptions; import java.util.Collection; @@ -16,6 +17,7 @@ private final DexApplication app; private final DexItemFactory dexItemFactory; + private final MainDexClasses mainDexClasses; private final SyntheticItems syntheticItems; // Set when a new AppInfo replaces a previous one. All public methods should verify that the @@ -23,23 +25,40 @@ private final BooleanBox obsolete; public static AppInfo createInitialAppInfo(DexApplication application) { - return new AppInfo(application, SyntheticItems.createInitialSyntheticItems(), new BooleanBox()); + return createInitialAppInfo(application, MainDexClasses.createEmptyMainDexClasses()); } - public AppInfo(DexApplication application, SyntheticItems.CommittedItems committedItems) { - this(application, committedItems.toSyntheticItems(), new BooleanBox()); + public static AppInfo createInitialAppInfo( + DexApplication application, MainDexClasses mainDexClasses) { + return new AppInfo( + application, + mainDexClasses, + SyntheticItems.createInitialSyntheticItems(), + new BooleanBox()); + } + + public AppInfo( + DexApplication application, + MainDexClasses mainDexClasses, + SyntheticItems.CommittedItems committedItems) { + this(application, mainDexClasses, committedItems.toSyntheticItems(), new BooleanBox()); } // For desugaring. // This is a view onto the app info and is the only place the pending synthetics are shared. AppInfo(CreateDesugaringViewOnAppInfo witness, AppInfo appInfo) { - this(appInfo.app, appInfo.syntheticItems, appInfo.obsolete); + this(appInfo.app, appInfo.mainDexClasses, appInfo.syntheticItems, appInfo.obsolete); assert witness != null; } - private AppInfo(DexApplication application, SyntheticItems syntheticItems, BooleanBox obsolete) { + private AppInfo( + DexApplication application, + MainDexClasses mainDexClasses, + SyntheticItems syntheticItems, + BooleanBox obsolete) { this.app = application; this.dexItemFactory = application.dexItemFactory; + this.mainDexClasses = mainDexClasses; this.syntheticItems = syntheticItems; this.obsolete = obsolete; } @@ -76,13 +95,20 @@ return dexItemFactory; } + public MainDexClasses getMainDexClasses() { + return mainDexClasses; + } + public SyntheticItems getSyntheticItems() { return syntheticItems; } - public void addSynthesizedClass(DexProgramClass clazz) { + public void addSynthesizedClass(DexProgramClass clazz, boolean addToMainDexClasses) { assert checkIfObsolete(); syntheticItems.addSyntheticClass(clazz); + if (addToMainDexClasses && !mainDexClasses.isEmpty()) { + mainDexClasses.add(clazz); + } } public Collection<DexProgramClass> synthesizedClasses() { @@ -189,11 +215,6 @@ return null; } - public boolean isInMainDexList(DexType type) { - assert checkIfObsolete(); - return app.mainDexList.contains(type); - } - public final FieldResolutionResult resolveField(DexField field, ProgramMethod context) { return resolveFieldOn(field.holder, field, context); }
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 f1b0dc2..68ce78b 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -15,6 +15,7 @@ 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.shaking.MainDexClasses; import com.android.tools.r8.utils.ListUtils; import com.android.tools.r8.utils.SetUtils; import com.android.tools.r8.utils.TraversalContinuation; @@ -46,15 +47,19 @@ } public static AppInfoWithClassHierarchy createInitialAppInfoWithClassHierarchy( - DexApplication application) { + DexApplication application, MainDexClasses mainDexClasses) { return new AppInfoWithClassHierarchy( - application, SyntheticItems.createInitialSyntheticItems().commit(application)); + application, + mainDexClasses, + SyntheticItems.createInitialSyntheticItems().commit(application)); } // For AppInfoWithLiveness. protected AppInfoWithClassHierarchy( - DexApplication application, SyntheticItems.CommittedItems committedItems) { - super(application, committedItems); + DexApplication application, + MainDexClasses mainDexClasses, + SyntheticItems.CommittedItems committedItems) { + super(application, mainDexClasses, committedItems); } // For desugaring. @@ -69,7 +74,8 @@ public AppInfoWithClassHierarchy rebuild(Function<DexApplication, DexApplication> fn) { DexApplication application = fn.apply(app()); - return new AppInfoWithClassHierarchy(application, getSyntheticItems().commit(application)); + return new AppInfoWithClassHierarchy( + application, getMainDexClasses(), getSyntheticItems().commit(application)); } @Override
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 d0a3643..2a181bc 100644 --- a/src/main/java/com/android/tools/r8/graph/AppView.java +++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -25,6 +25,7 @@ import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.KeepInfoCollection; import com.android.tools.r8.shaking.LibraryModeledPredicate; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.shaking.RootSetBuilder.RootSet; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.OptionalBool; @@ -129,8 +130,14 @@ } public static AppView<AppInfoWithClassHierarchy> createForR8(DexApplication application) { + return createForR8(application, MainDexClasses.createEmptyMainDexClasses()); + } + + public static AppView<AppInfoWithClassHierarchy> createForR8( + DexApplication application, MainDexClasses mainDexClasses) { AppInfoWithClassHierarchy appInfo = - AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(application); + AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy( + application, mainDexClasses); return new AppView<>( appInfo, WholeProgramOptimizations.ON, defaultPrefixRewritingMapper(appInfo)); }
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 c40931a..b74a480 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -24,6 +24,7 @@ import com.android.tools.r8.ir.code.Position; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.conversion.MethodProcessor; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; @@ -39,6 +40,7 @@ import java.util.BitSet; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; @@ -199,18 +201,21 @@ } public void write( - DexEncodedMethod method, - MethodVisitor visitor, - NamingLens namingLens, + ProgramMethod method, + int classFileVersion, AppView<?> appView, - int classFileVersion) { + NamingLens namingLens, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + DexItemFactory dexItemFactory = appView.dexItemFactory(); GraphLens graphLens = appView.graphLens(); InitClassLens initClassLens = appView.initClassLens(); InternalOptions options = appView.options(); CfLabel parameterLabel = null; - if (shouldAddParameterNames(method, appView)) { + if (shouldAddParameterNames(method.getDefinition(), appView)) { parameterLabel = new CfLabel(); - parameterLabel.write(visitor, graphLens, initClassLens, namingLens); + parameterLabel.write( + method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor); } for (CfInstruction instruction : instructions) { if (instruction instanceof CfFrame @@ -218,7 +223,8 @@ || (classFileVersion == V1_6 && !options.shouldKeepStackMapTable()))) { continue; } - instruction.write(visitor, graphLens, initClassLens, namingLens); + instruction.write( + method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor); } visitor.visitEnd(); visitor.visitMaxs(maxStack, maxLocals); @@ -227,19 +233,21 @@ Label end = tryCatch.end.getLabel(); for (int i = 0; i < tryCatch.guards.size(); i++) { DexType guard = tryCatch.guards.get(i); + DexType rewrittenGuard = graphLens.lookupType(guard); Label target = tryCatch.targets.get(i).getLabel(); visitor.visitTryCatchBlock( start, end, target, - guard == options.itemFactory.throwableType + rewrittenGuard == options.itemFactory.throwableType ? null - : namingLens.lookupInternalName(guard)); + : namingLens.lookupInternalName(rewrittenGuard)); } } if (parameterLabel != null) { assert localVariables.isEmpty(); - for (Entry<Integer, DebugLocalInfo> entry : method.getParameterInfo().entrySet()) { + Map<Integer, DebugLocalInfo> parameterInfo = method.getDefinition().getParameterInfo(); + for (Entry<Integer, DebugLocalInfo> entry : parameterInfo.entrySet()) { writeLocalVariableEntry( visitor, namingLens, entry.getValue(), parameterLabel, parameterLabel, entry.getKey()); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java index d6d69a6..67870ab 100644 --- a/src/main/java/com/android/tools/r8/graph/DexApplication.java +++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -14,20 +14,15 @@ import com.android.tools.r8.utils.ProgramClassCollection; import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; public abstract class DexApplication { public final ImmutableList<DataResourceProvider> dataResourceProviders; - public final ImmutableSet<DexType> mainDexList; - private final ClassNameMapper proguardMap; public final Timing timing; @@ -42,13 +37,11 @@ DexApplication( ClassNameMapper proguardMap, ImmutableList<DataResourceProvider> dataResourceProviders, - ImmutableSet<DexType> mainDexList, InternalOptions options, DexString highestSortingString, Timing timing) { this.proguardMap = proguardMap; this.dataResourceProviders = dataResourceProviders; - this.mainDexList = mainDexList; this.options = options; this.dexItemFactory = options.itemFactory; this.highestSortingString = highestSortingString; @@ -57,6 +50,22 @@ public abstract Builder<?> builder(); + public DexDefinitionSupplier getDefinitionsSupplier( + SyntheticDefinitionsProvider syntheticDefinitionsProvider) { + DexApplication self = this; + return new DexDefinitionSupplier() { + @Override + public DexClass definitionFor(DexType type) { + return syntheticDefinitionsProvider.definitionFor(type, self::definitionFor); + } + + @Override + public DexItemFactory dexItemFactory() { + return self.dexItemFactory; + } + }; + } + // Reorder classes randomly. Note that the order of classes in program or library // class collections should not matter for compilation of valid code and when running // with assertions enabled we reorder the classes randomly to catch possible issues. @@ -133,7 +142,6 @@ final Timing timing; DexString highestSortingString; - final Set<DexType> mainDexList = Sets.newIdentityHashSet(); private final Collection<DexProgramClass> synthesizedClasses; public Builder(InternalOptions options, Timing timing) { @@ -153,7 +161,6 @@ highestSortingString = application.highestSortingString; options = application.options; dexItemFactory = application.dexItemFactory; - mainDexList.addAll(application.mainDexList); synthesizedClasses = new ArrayList<>(); } @@ -185,14 +192,10 @@ return self(); } - public synchronized T addSynthesizedClass( - DexProgramClass synthesizedClass, boolean addToMainDexList) { + public synchronized T addSynthesizedClass(DexProgramClass synthesizedClass) { assert synthesizedClass.isProgramClass() : "All synthesized classes must be program classes"; addProgramClass(synthesizedClass); synthesizedClasses.add(synthesizedClass); - if (addToMainDexList && !mainDexList.isEmpty()) { - mainDexList.add(synthesizedClass.type); - } return self(); } @@ -204,20 +207,6 @@ return synthesizedClasses; } - public Set<DexType> getMainDexList() { - return mainDexList; - } - - public Builder<T> addToMainDexList(DexType mainDex) { - mainDexList.add(mainDex); - return this; - } - - public Builder<T> addToMainDexList(Collection<DexType> mainDexList) { - this.mainDexList.addAll(mainDexList); - return this; - } - public abstract DexApplication build(); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java index 6716297..b8a1e8f 100644 --- a/src/main/java/com/android/tools/r8/graph/DexCode.java +++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -16,6 +16,7 @@ import com.android.tools.r8.ir.code.Position; import com.android.tools.r8.ir.conversion.DexSourceCode; import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.conversion.MethodProcessor; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.origin.Origin; @@ -403,11 +404,15 @@ return builder.toString(); } - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, + ProgramMethod context, + GraphLens graphLens, + LensCodeRewriterUtils rewriter) { highestSortingString = null; for (Instruction insn : instructions) { assert !insn.isDexItemBasedConstString(); - insn.collectIndexedItems(indexedItems); + insn.collectIndexedItems(indexedItems, context, graphLens, rewriter); if (insn.isConstString()) { updateHighestSortingString(insn.asConstString().getString()); } else if (insn.isConstStringJumbo()) { @@ -415,11 +420,11 @@ } } if (debugInfo != null) { - getDebugInfoForWriting().collectIndexedItems(indexedItems); + getDebugInfoForWriting().collectIndexedItems(indexedItems, graphLens); } if (handlers != null) { for (TryHandler handler : handlers) { - handler.collectIndexedItems(indexedItems); + handler.collectIndexedItems(indexedItems, graphLens); } } } @@ -548,9 +553,9 @@ return false; } - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) { for (TypeAddrPair pair : pairs) { - pair.collectIndexedItems(indexedItems); + pair.collectIndexedItems(indexedItems, graphLens); } } @@ -590,8 +595,9 @@ this.addr = addr; } - public void collectIndexedItems(IndexedItemCollection indexedItems) { - type.collectIndexedItems(indexedItems); + public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) { + DexType rewritten = graphLens.lookupType(type); + rewritten.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java index 20fd6e6..0e59082 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java +++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -13,7 +13,7 @@ abstract public class DexDebugEvent extends DexItem { public static final DexDebugEvent[] EMPTY_ARRAY = {}; - public void collectIndexedItems(IndexedItemCollection collection) { + public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) { // Empty by default. } @@ -220,12 +220,13 @@ } @Override - public void collectIndexedItems(IndexedItemCollection collection) { + public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) { if (name != null) { name.collectIndexedItems(collection); } if (type != null) { - type.collectIndexedItems(collection); + DexType rewritten = graphLens.lookupType(type); + rewritten.collectIndexedItems(collection); } if (signature != null) { signature.collectIndexedItems(collection); @@ -359,7 +360,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection collection) { + public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) { fileName.collectIndexedItems(collection); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java index 51ad23c..ed4f2c5 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java +++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -54,14 +54,14 @@ return false; } - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) { for (DexString parameter : parameters) { if (parameter != null) { parameter.collectIndexedItems(indexedItems); } } for (DexDebugEvent event : events) { - event.collectIndexedItems(indexedItems); + event.collectIndexedItems(indexedItems, graphLens); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java index cc91bcd..9391a83 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java +++ b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
@@ -31,6 +31,10 @@ return type == context.type ? context : contextIndependentDefinitionFor(type); } + default DexClass definitionFor(DexType type, ProgramMethod context) { + return definitionFor(type, context.getHolder()); + } + /** * Lookup for the program definition of a type from a given context. *
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 4b6fd50..7683f12 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -7,7 +7,6 @@ import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO; -import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; @@ -87,14 +86,6 @@ this.kotlinMemberInfo = kotlinMemberInfo; } - public void collectIndexedItems(IndexedItemCollection indexedItems) { - field.collectIndexedItems(indexedItems); - annotations().collectIndexedItems(indexedItems); - if (accessFlags.isStatic()) { - getStaticValue().collectIndexedItems(indexedItems); - } - } - @Override void collectMixedSectionItems(MixedSectionCollection mixedItems) { annotations().collectMixedSectionItems(mixedItems);
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 ce6934a..2ca1b48 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -13,24 +13,30 @@ import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO; import com.android.tools.r8.cf.code.CfConstNull; +import com.android.tools.r8.cf.code.CfConstNumber; import com.android.tools.r8.cf.code.CfConstString; +import com.android.tools.r8.cf.code.CfInstanceOf; import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.cf.code.CfInvoke; import com.android.tools.r8.cf.code.CfLoad; +import com.android.tools.r8.cf.code.CfLogicalBinop; import com.android.tools.r8.cf.code.CfNew; +import com.android.tools.r8.cf.code.CfReturn; import com.android.tools.r8.cf.code.CfStackInstruction; import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; import com.android.tools.r8.cf.code.CfStore; import com.android.tools.r8.cf.code.CfThrow; import com.android.tools.r8.code.Const; import com.android.tools.r8.code.ConstString; +import com.android.tools.r8.code.InstanceOf; import com.android.tools.r8.code.Instruction; import com.android.tools.r8.code.InvokeDirect; import com.android.tools.r8.code.InvokeStatic; import com.android.tools.r8.code.NewInstance; +import com.android.tools.r8.code.Return; import com.android.tools.r8.code.Throw; +import com.android.tools.r8.code.XorIntLit8; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.JumboStringRewriter; import com.android.tools.r8.dex.MethodToCodeObjectMapping; import com.android.tools.r8.dex.MixedSectionCollection; @@ -38,6 +44,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.Invoke; +import com.android.tools.r8.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring.DexFieldWithAccess; @@ -61,6 +68,7 @@ import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.shaking.AnnotationRemover; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.OptionalBool; import com.android.tools.r8.utils.Pair; @@ -648,20 +656,6 @@ return "Encoded method " + method; } - public void collectIndexedItems(IndexedItemCollection indexedItems) { - checkIfObsolete(); - this.method.collectIndexedItems(indexedItems); - if (code != null) { - if (code.isDexCode()) { - code.asDexCode().collectIndexedItems(indexedItems); - } else { - assert false; - } - } - annotations().collectIndexedItems(indexedItems); - parameterAnnotationsList.collectIndexedItems(indexedItems); - } - @Override void collectMixedSectionItems(MixedSectionCollection mixedItems) { mixedItems.visit(this); @@ -850,10 +844,46 @@ } public DexCode buildEmptyThrowingDexCode() { - Instruction insn[] = {new Const(0, 0), new Throw(0)}; + Instruction[] insn = {new Const(0, 0), new Throw(0)}; return generateCodeFromTemplate(1, 0, insn); } + public Code buildInstanceOfCode(DexType type, boolean negate, InternalOptions options) { + return options.isGeneratingClassFiles() + ? buildInstanceOfCfCode(type, negate) + : buildInstanceOfDexCode(type, negate); + } + + public CfCode buildInstanceOfCfCode(DexType type, boolean negate) { + CfInstruction[] instructions = new CfInstruction[3 + BooleanUtils.intValue(negate) * 2]; + int i = 0; + instructions[i++] = new CfLoad(ValueType.OBJECT, 0); + instructions[i++] = new CfInstanceOf(type); + if (negate) { + instructions[i++] = new CfConstNumber(1, ValueType.INT); + instructions[i++] = new CfLogicalBinop(CfLogicalBinop.Opcode.Xor, NumericType.INT); + } + instructions[i] = new CfReturn(ValueType.INT); + return new CfCode( + method.holder, + 1 + BooleanUtils.intValue(negate), + method.getArity() + 1, + Arrays.asList(instructions), + Collections.emptyList(), + Collections.emptyList()); + } + + public DexCode buildInstanceOfDexCode(DexType type, boolean negate) { + Instruction[] instructions = new Instruction[2 + BooleanUtils.intValue(negate)]; + int i = 0; + instructions[i++] = new InstanceOf(0, 0, type); + if (negate) { + instructions[i++] = new XorIntLit8(0, 0, 1); + } + instructions[i] = new Return(0); + return generateCodeFromTemplate(1, 0, instructions); + } + public DexEncodedMethod toMethodThatLogsError(AppView<?> appView) { if (appView.options().isGeneratingDex()) { return toMethodThatLogsErrorDexCode(appView.dexItemFactory());
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java index 999f261..493bea3 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -31,6 +31,10 @@ } } + public DexString getName() { + return name; + } + public DexTypeList getParameters() { return proto.parameters; }
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 90c37ed..a285398 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.kotlin.KotlinClassLevelInfo; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.origin.Origin; @@ -233,7 +234,8 @@ return originKind == Kind.CF; } - public void collectIndexedItems(IndexedItemCollection indexedItems) { + public void collectIndexedItems( + IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) { if (indexedItems.addClass(this)) { type.collectIndexedItems(indexedItems); if (superType != null) { @@ -254,8 +256,8 @@ for (InnerClassAttribute attribute : getInnerClasses()) { attribute.collectIndexedItems(indexedItems); } - forEachField(field -> field.collectIndexedItems(indexedItems)); - forEachMethod(method -> method.collectIndexedItems(indexedItems)); + forEachProgramField(field -> field.collectIndexedItems(indexedItems)); + forEachProgramMethod(method -> method.collectIndexedItems(indexedItems, graphLens, rewriter)); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java index 81c4dc5..fc14405 100644 --- a/src/main/java/com/android/tools/r8/graph/DexType.java +++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -286,21 +286,37 @@ // TODO(b/158159959): Remove usage of name-based identification. public boolean isD8R8SynthesizedClassType() { String name = toSourceString(); - return name.contains(COMPANION_CLASS_NAME_SUFFIX) - || name.contains(ENUM_UNBOXING_UTILITY_CLASS_NAME) + // The synthesized classes listed here must always be unique to a program context and thus + // never duplicated for distinct inputs. + return + // Hygienic suffix. + name.contains(COMPANION_CLASS_NAME_SUFFIX) + // Only generated in core lib. || name.contains(EMULATE_LIBRARY_CLASS_NAME_SUFFIX) - || name.contains(DISPATCH_CLASS_NAME_SUFFIX) || name.contains(TYPE_WRAPPER_SUFFIX) || name.contains(VIVIFIED_TYPE_WRAPPER_SUFFIX) - || name.contains(LAMBDA_CLASS_NAME_PREFIX) - || name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX) - || name.contains(OutlineOptions.CLASS_NAME) - || name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME) - || name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME) - || name.contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX) || name.contains(DesugaredLibraryRetargeter.DESUGAR_LIB_RETARGET_CLASS_NAME_PREFIX) - || name.contains(ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME) - || oldSynthesizedName(name); + // Non-hygienic types. + || isSynthesizedTypeThatCouldBeDuplicated(name); + } + + public boolean isLegacySynthesizedTypeAllowedDuplication() { + String name = toSourceString(); + return isSynthesizedTypeThatCouldBeDuplicated(name) || oldSynthesizedName(name); + } + + private static boolean isSynthesizedTypeThatCouldBeDuplicated(String name) { + // Any entry that is removed from here must be added to OLD_SYNTHESIZED_NAMES to ensure that + // newer releases can be used to merge previous builds. + return name.contains(ENUM_UNBOXING_UTILITY_CLASS_NAME) // Global singleton. + || name.contains(LAMBDA_CLASS_NAME_PREFIX) // Could collide. + || name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX) // Could collide. + || name.contains(DISPATCH_CLASS_NAME_SUFFIX) // Shared on reference. + || name.contains(OutlineOptions.CLASS_NAME) // Global singleton. + || name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME) // Global singleton. + || name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME) // Global singleton. + || name.contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX) // Shared on reference. + || name.contains(ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME); // Global singleton. } private boolean oldSynthesizedName(String name) {
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java index fe85d28..3295733 100644 --- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java +++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -13,7 +13,6 @@ import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; @@ -40,14 +39,12 @@ ImmutableList<DexClasspathClass> classpathClasses, ImmutableList<DexLibraryClass> libraryClasses, ImmutableList<DataResourceProvider> dataResourceProviders, - ImmutableSet<DexType> mainDexList, InternalOptions options, DexString highestSortingString, Timing timing) { super( proguardMap, dataResourceProviders, - mainDexList, options, highestSortingString, timing); @@ -74,22 +71,6 @@ return classpathClasses; } - public DexDefinitionSupplier getDefinitionsSupplier( - SyntheticDefinitionsProvider syntheticDefinitionsProvider) { - DirectMappedDexApplication self = this; - return new DexDefinitionSupplier() { - @Override - public DexClass definitionFor(DexType type) { - return syntheticDefinitionsProvider.definitionFor(type, self::definitionFor); - } - - @Override - public DexItemFactory dexItemFactory() { - return self.dexItemFactory; - } - }; - } - @Override public DexClass definitionFor(DexType type) { assert type.isClassType() : "Cannot lookup definition for type: " + type; @@ -256,7 +237,6 @@ classpathClasses, libraryClasses, ImmutableList.copyOf(dataResourceProviders), - ImmutableSet.copyOf(mainDexList), options, highestSortingString, timing);
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 35917f5..19ac497 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java +++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -22,6 +22,8 @@ ProgramMethod getUniqueReadContext(); + boolean hasKnownWriteContexts(); + void forEachIndirectAccess(Consumer<DexField> consumer); void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java index 9d19406..b3f9c25 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java +++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java
@@ -10,6 +10,8 @@ /** Provides immutable access to {@link FieldAccessInfoCollectionImpl}. */ public interface FieldAccessInfoCollection<T extends FieldAccessInfo> { + void destroyAccessContexts(); + void flattenAccessContexts(); boolean contains(DexField field);
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 6224914..c82fcf0 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java +++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
@@ -16,6 +16,11 @@ private Map<DexField, FieldAccessInfoImpl> infos = new IdentityHashMap<>(); @Override + public void destroyAccessContexts() { + infos.values().forEach(FieldAccessInfoImpl::destroyAccessContexts); + } + + @Override public void flattenAccessContexts() { infos.values().forEach(FieldAccessInfoImpl::flattenAccessContexts); }
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 ae8a212..023e423 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.graph.AbstractAccessContexts.ConcreteAccessContexts; import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.collect.Sets; import java.util.IdentityHashMap; @@ -36,37 +37,28 @@ // Maps every direct and indirect reference in a read-context to the set of methods in which that // reference appears. - private Map<DexField, ProgramMethodSet> readsWithContexts; + private AbstractAccessContexts readsWithContexts = AbstractAccessContexts.empty(); // Maps every direct and indirect reference in a write-context to the set of methods in which that // reference appears. - private Map<DexField, ProgramMethodSet> writesWithContexts; + private AbstractAccessContexts writesWithContexts = AbstractAccessContexts.empty(); public FieldAccessInfoImpl(DexField field) { this.field = field; } + void destroyAccessContexts() { + readsWithContexts = AbstractAccessContexts.unknown(); + writesWithContexts = AbstractAccessContexts.unknown(); + } + void flattenAccessContexts() { flattenAccessContexts(readsWithContexts); flattenAccessContexts(writesWithContexts); } - private void flattenAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) { - if (accessesWithContexts != null) { - ProgramMethodSet flattenedAccessContexts = - accessesWithContexts.computeIfAbsent(field, ignore -> ProgramMethodSet.create()); - accessesWithContexts.forEach( - (access, contexts) -> { - if (access != field) { - flattenedAccessContexts.addAll(contexts); - } - }); - accessesWithContexts.clear(); - if (!flattenedAccessContexts.isEmpty()) { - accessesWithContexts.put(field, flattenedAccessContexts); - } - assert accessesWithContexts.size() <= 1; - } + private void flattenAccessContexts(AbstractAccessContexts accessesWithContexts) { + accessesWithContexts.flattenAccessContexts(field); } @Override @@ -81,33 +73,24 @@ @Override public int getNumberOfReadContexts() { - return getNumberOfAccessContexts(readsWithContexts); + return readsWithContexts.getNumberOfAccessContexts(); } @Override public int getNumberOfWriteContexts() { - return getNumberOfAccessContexts(writesWithContexts); - } - - private int getNumberOfAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) { - if (accessesWithContexts == null) { - return 0; - } - if (accessesWithContexts.size() == 1) { - return accessesWithContexts.values().iterator().next().size(); - } - throw new Unreachable("Should only be querying the number of access contexts after flattening"); + return writesWithContexts.getNumberOfAccessContexts(); } @Override public ProgramMethod getUniqueReadContext() { - if (readsWithContexts != null && readsWithContexts.size() == 1) { - ProgramMethodSet contexts = readsWithContexts.values().iterator().next(); - if (contexts.size() == 1) { - return contexts.iterator().next(); - } - } - return null; + return readsWithContexts.isConcrete() + ? readsWithContexts.asConcrete().getUniqueAccessContext() + : null; + } + + @Override + public boolean hasKnownWriteContexts() { + return !writesWithContexts.isTop(); } @Override @@ -115,76 +98,71 @@ // 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<DexField> visited = Sets.newIdentityHashSet(); - forEachAccessInMap( - readsWithContexts, access -> access != field && visited.add(access), consumer); - forEachAccessInMap( - writesWithContexts, access -> access != field && visited.add(access), consumer); + forEachIndirectAccess(consumer, readsWithContexts, visited); + forEachIndirectAccess(consumer, writesWithContexts, visited); } - private static void forEachAccessInMap( - Map<DexField, ProgramMethodSet> accessesWithContexts, - Predicate<DexField> predicate, - Consumer<DexField> consumer) { - if (accessesWithContexts != null) { - accessesWithContexts.forEach( - (access, contexts) -> { - if (predicate.test(access)) { - consumer.accept(access); - } - }); + private void forEachIndirectAccess( + Consumer<DexField> consumer, + AbstractAccessContexts accessesWithContexts, + Set<DexField> visited) { + if (accessesWithContexts.isBottom()) { + return; } + if (accessesWithContexts.isConcrete()) { + accessesWithContexts + .asConcrete() + .forEachAccess(consumer, access -> access != field && visited.add(access)); + return; + } + throw new Unreachable("Should never be iterating the indirect accesses when they are unknown"); } @Override public void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer) { Map<DexField, ProgramMethodSet> indirectAccessesWithContexts = new IdentityHashMap<>(); - extendAccessesWithContexts( - indirectAccessesWithContexts, access -> access != field, readsWithContexts); - extendAccessesWithContexts( - indirectAccessesWithContexts, access -> access != field, writesWithContexts); + addAccessesWithContextsToMap( + readsWithContexts, access -> access != field, indirectAccessesWithContexts); + addAccessesWithContextsToMap( + writesWithContexts, access -> access != field, indirectAccessesWithContexts); indirectAccessesWithContexts.forEach(consumer); } - private void extendAccessesWithContexts( + private static void addAccessesWithContextsToMap( + AbstractAccessContexts accessesWithContexts, + Predicate<DexField> predicate, + Map<DexField, ProgramMethodSet> out) { + if (accessesWithContexts.isBottom()) { + return; + } + if (accessesWithContexts.isConcrete()) { + extendAccessesWithContexts( + accessesWithContexts.asConcrete().getAccessesWithContexts(), predicate, out); + return; + } + throw new Unreachable("Should never be iterating the indirect accesses when they are unknown"); + } + + private static void extendAccessesWithContexts( Map<DexField, ProgramMethodSet> accessesWithContexts, Predicate<DexField> predicate, - Map<DexField, ProgramMethodSet> extension) { - if (extension != null) { - extension.forEach( - (access, contexts) -> { - if (predicate.test(access)) { - accessesWithContexts - .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) - .addAll(contexts); - } - }); - } + Map<DexField, ProgramMethodSet> out) { + accessesWithContexts.forEach( + (access, contexts) -> { + if (predicate.test(access)) { + out.computeIfAbsent(access, ignore -> ProgramMethodSet.create()).addAll(contexts); + } + }); } @Override public void forEachReadContext(Consumer<ProgramMethod> consumer) { - forEachAccessContext(readsWithContexts, consumer); + readsWithContexts.forEachAccessContext(consumer); } @Override public void forEachWriteContext(Consumer<ProgramMethod> consumer) { - forEachAccessContext(writesWithContexts, consumer); - } - - private void forEachAccessContext( - 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. - ProgramMethodSet visited = ProgramMethodSet.create(); - if (accessesWithContexts != null) { - for (ProgramMethodSet encodedAccessContexts : accessesWithContexts.values()) { - for (ProgramMethod encodedAccessContext : encodedAccessContexts) { - if (visited.add(encodedAccessContext)) { - consumer.accept(encodedAccessContext); - } - } - } - } + writesWithContexts.forEachAccessContext(consumer); } @Override @@ -199,7 +177,7 @@ /** Returns true if this field is read by the program. */ @Override public boolean isRead() { - return (readsWithContexts != null && !readsWithContexts.isEmpty()) || isReadFromAnnotation(); + return !readsWithContexts.isEmpty() || isReadFromAnnotation(); } @Override @@ -223,7 +201,7 @@ /** Returns true if this field is written by the program. */ @Override public boolean isWritten() { - return writesWithContexts != null && !writesWithContexts.isEmpty(); + return !writesWithContexts.isEmpty(); } @Override @@ -240,16 +218,7 @@ */ @Override public boolean isWrittenInMethodSatisfying(Predicate<ProgramMethod> predicate) { - if (writesWithContexts != null) { - for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) { - for (ProgramMethod encodedWriteContext : encodedWriteContexts) { - if (predicate.test(encodedWriteContext)) { - return true; - } - } - } - } - return false; + return writesWithContexts.isAccessedInMethodSatisfying(predicate); } /** @@ -258,16 +227,7 @@ */ @Override public boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) { - if (writesWithContexts != null) { - for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) { - for (ProgramMethod encodedWriteContext : encodedWriteContexts) { - if (!predicate.test(encodedWriteContext)) { - return false; - } - } - } - } - return true; + return writesWithContexts.isAccessedOnlyInMethodSatisfying(predicate); } /** @@ -275,71 +235,42 @@ */ @Override public boolean isWrittenOutside(DexEncodedMethod method) { - if (writesWithContexts != null) { - for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) { - for (ProgramMethod encodedWriteContext : encodedWriteContexts) { - if (encodedWriteContext.getDefinition() != method) { - return true; - } - } - } + return writesWithContexts.isAccessedOutside(method); + } + + public boolean recordRead(DexField access, ProgramMethod context) { + if (readsWithContexts.isBottom()) { + readsWithContexts = new ConcreteAccessContexts(); + } + if (readsWithContexts.isConcrete()) { + return readsWithContexts.asConcrete().recordAccess(access, context); } return false; } - public boolean recordRead(DexField access, ProgramMethod context) { - if (readsWithContexts == null) { - readsWithContexts = new IdentityHashMap<>(); - } - return readsWithContexts - .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) - .add(context); - } - public boolean recordWrite(DexField access, ProgramMethod context) { - if (writesWithContexts == null) { - writesWithContexts = new IdentityHashMap<>(); + if (writesWithContexts.isBottom()) { + writesWithContexts = new ConcreteAccessContexts(); } - return writesWithContexts - .computeIfAbsent(access, ignore -> ProgramMethodSet.create()) - .add(context); + if (writesWithContexts.isConcrete()) { + return writesWithContexts.asConcrete().recordAccess(access, context); + } + return false; } public void clearReads() { - readsWithContexts = null; + readsWithContexts = AbstractAccessContexts.empty(); } public void clearWrites() { - writesWithContexts = null; + writesWithContexts = AbstractAccessContexts.empty(); } public FieldAccessInfoImpl rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) { FieldAccessInfoImpl rewritten = new FieldAccessInfoImpl(lens.lookupField(field)); rewritten.flags = flags; - if (readsWithContexts != null) { - rewritten.readsWithContexts = new IdentityHashMap<>(); - readsWithContexts.forEach( - (access, contexts) -> { - ProgramMethodSet newContexts = - rewritten.readsWithContexts.computeIfAbsent( - lens.lookupField(access), ignore -> ProgramMethodSet.create()); - for (ProgramMethod context : contexts) { - newContexts.add(lens.mapProgramMethod(context, definitions)); - } - }); - } - if (writesWithContexts != null) { - rewritten.writesWithContexts = new IdentityHashMap<>(); - writesWithContexts.forEach( - (access, contexts) -> { - ProgramMethodSet newContexts = - rewritten.writesWithContexts.computeIfAbsent( - lens.lookupField(access), ignore -> ProgramMethodSet.create()); - for (ProgramMethod context : contexts) { - newContexts.add(lens.mapProgramMethod(context, definitions)); - } - }); - } + rewritten.readsWithContexts = readsWithContexts.rewrittenWithLens(definitions, lens); + rewritten.writesWithContexts = writesWithContexts.rewrittenWithLens(definitions, lens); return rewritten; } }
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java index 2491193..14a4e95 100644 --- a/src/main/java/com/android/tools/r8/graph/GraphLens.java +++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.graph; +import com.android.tools.r8.horizontalclassmerging.ClassMerger; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens; import com.android.tools.r8.shaking.KeepInfoCollection; @@ -408,6 +409,12 @@ if (field.field.match(dexItemFactory.objectMembers.clinitField)) { continue; } + + // TODO(b/167947782): Should be a general check to see if the field is D8/R8 synthesized. + if (field.toReference().name.toSourceString().equals(ClassMerger.CLASS_ID_FIELD_NAME)) { + continue; + } + DexField originalField = getOriginalFieldSignature(field.field); assert originalFields.contains(originalField) : "Unable to map field `" + field.field.toSourceString() + "` back to original program";
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java index 1721860..ce5ff83 100644 --- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java +++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -15,7 +15,6 @@ import com.android.tools.r8.utils.ProgramClassCollection; import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -34,14 +33,12 @@ ImmutableList<DataResourceProvider> dataResourceProviders, ClasspathClassCollection classpathClasses, LibraryClassCollection libraryClasses, - ImmutableSet<DexType> mainDexList, InternalOptions options, DexString highestSortingString, Timing timing) { super( proguardMap, dataResourceProviders, - mainDexList, options, highestSortingString, timing); @@ -236,7 +233,6 @@ ImmutableList.copyOf(dataResourceProviders), classpathClasses, libraryClasses, - ImmutableSet.copyOf(mainDexList), options, highestSortingString, timing);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java index c7edad2..949fd47 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -269,12 +269,28 @@ @Override public DexEncodedMethod replaceDirectMethod( DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) { - for (int i = 0; i < directMethods.length; i++) { - DexEncodedMethod directMethod = directMethods[i]; - if (method.match(directMethod)) { - DexEncodedMethod newMethod = replacement.apply(directMethod); - assert belongsToDirectPool(newMethod); - directMethods[i] = newMethod; + DexEncodedMethod newMethod = replaceMethod(method, replacement, directMethods); + assert newMethod == null || belongsToDirectPool(newMethod); + return newMethod; + } + + @Override + public DexEncodedMethod replaceVirtualMethod( + DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) { + DexEncodedMethod newMethod = replaceMethod(method, replacement, virtualMethods); + assert newMethod == null || belongsToVirtualPool(newMethod); + return newMethod; + } + + private DexEncodedMethod replaceMethod( + DexMethod reference, + Function<DexEncodedMethod, DexEncodedMethod> replacement, + DexEncodedMethod[] methods) { + for (int i = 0; i < methods.length; i++) { + DexEncodedMethod method = methods[i]; + if (reference.match(method)) { + DexEncodedMethod newMethod = replacement.apply(method); + methods[i] = newMethod; return newMethod; } }
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java index b1a8f8e..312cec2 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java +++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -212,6 +212,12 @@ return backing.replaceDirectMethod(method, replacement); } + public DexEncodedMethod replaceVirtualMethod( + DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) { + resetVirtualMethodCaches(); + return backing.replaceVirtualMethod(method, replacement); + } + public void replaceMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) { resetCaches(); backing.replaceMethods(replacement);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java index 0b3f435..601306c 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
@@ -113,6 +113,9 @@ abstract DexEncodedMethod replaceDirectMethod( DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement); + abstract DexEncodedMethod replaceVirtualMethod( + DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement); + abstract DexEncodedMethod replaceDirectMethodWithVirtualMethod( DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java index 19c3cec..d95a723 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -286,13 +286,26 @@ @Override DexEncodedMethod replaceDirectMethod( DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) { + return replaceMethod(method, replacement, this::belongsToDirectPool); + } + + @Override + DexEncodedMethod replaceVirtualMethod( + DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) { + return replaceMethod(method, replacement, this::belongsToVirtualPool); + } + + private DexEncodedMethod replaceMethod( + DexMethod method, + Function<DexEncodedMethod, DexEncodedMethod> replacement, + Predicate<DexEncodedMethod> predicate) { Wrapper<DexMethod> key = wrap(method); DexEncodedMethod existing = methodMap.get(key); - if (existing == null || belongsToVirtualPool(existing)) { + if (existing == null || !predicate.test(existing)) { return null; } DexEncodedMethod newMethod = replacement.apply(existing); - assert belongsToDirectPool(newMethod); + assert predicate.test(newMethod); replace(key, newMethod); return newMethod; }
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java index 60c06cc..28ab2ca 100644 --- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java +++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
@@ -16,6 +16,8 @@ void forEachClassWithKnownAllocationSites( BiConsumer<DexProgramClass, Set<DexEncodedMethod>> consumer); + boolean hasInstantiatedStrictSubtype(DexProgramClass clazz); + boolean isAllocationSitesKnown(DexProgramClass clazz); boolean isInstantiatedDirectly(DexProgramClass clazz);
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java index fb6e5d1..fa105e6 100644 --- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java +++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -93,6 +93,7 @@ } /** True if there might exist an instantiated (strict) subtype of the given type. */ + @Override public boolean hasInstantiatedStrictSubtype(DexProgramClass clazz) { if (instantiatedHierarchy.get(clazz.type) != null) { return true;
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java index 33f3b90..ecc7505 100644 --- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java +++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -5,6 +5,7 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.NamingLens; import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2IntMap; @@ -23,8 +24,10 @@ private final static int NOT_FOUND = -1; private final static int NOT_SET = -2; + private final GraphLens graphLens; private final NamingLens namingLens; private final InitClassLens initClassLens; + private final LensCodeRewriterUtils lensCodeRewriter; // Sorted collection of objects mapped to their offsets. private final DexProgramClass[] classes; @@ -39,7 +42,8 @@ private DexString firstJumboString; public ObjectToOffsetMapping( - DexApplication application, + AppInfo appInfo, + GraphLens graphLens, NamingLens namingLens, InitClassLens initClassLens, Collection<DexProgramClass> classes, @@ -50,7 +54,7 @@ Collection<DexString> strings, Collection<DexCallSite> callSites, Collection<DexMethodHandle> methodHandles) { - assert application != null; + assert appInfo != null; assert classes != null; assert protos != null; assert types != null; @@ -60,9 +64,11 @@ assert callSites != null; assert methodHandles != null; assert initClassLens != null; + this.graphLens = graphLens; this.namingLens = namingLens; this.initClassLens = initClassLens; - this.classes = sortClasses(application, classes, namingLens); + this.lensCodeRewriter = new LensCodeRewriterUtils(appInfo, graphLens); + this.classes = sortClasses(appInfo, classes, namingLens); this.protos = createSortedMap(protos, compare(namingLens), this::failOnOverflow); this.types = createSortedMap(types, compare(namingLens), this::failOnOverflow); this.methods = createSortedMap(methods, compare(namingLens), this::failOnOverflow); @@ -114,11 +120,11 @@ private final static int UNKNOWN_DEPTH = -1; - private final DexApplication application; + private final AppInfo appInfo; private final Reference2IntMap<DexProgramClass> depthOfClasses = new Reference2IntOpenHashMap<>(); - ProgramClassDepthsMemoized(DexApplication application) { - this.application = application; + ProgramClassDepthsMemoized(AppInfo appInfo) { + this.appInfo = appInfo; depthOfClasses.defaultReturnValue(UNKNOWN_DEPTH); } @@ -134,13 +140,13 @@ maxDepth = 0; } else { maxDepth = 1; - DexProgramClass superClass = application.programDefinitionFor(superType); + DexProgramClass superClass = appInfo.programDefinitionFor(superType, programClass); if (superClass != null) { maxDepth = getDepth(superClass); } } for (DexType inf : programClass.interfaces.values) { - DexProgramClass infClass = application.programDefinitionFor(inf); + DexProgramClass infClass = appInfo.programDefinitionFor(inf, programClass); maxDepth = Math.max(maxDepth, infClass == null ? 1 : getDepth(infClass)); } depth = maxDepth + 1; @@ -152,9 +158,9 @@ } private static DexProgramClass[] sortClasses( - DexApplication application, Collection<DexProgramClass> classes, NamingLens namingLens) { + AppInfo appInfo, Collection<DexProgramClass> classes, NamingLens namingLens) { // Collect classes in subtyping order, based on a sorted list of classes to start with. - ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(application); + ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(appInfo); List<DexProgramClass> sortedClasses = classes.stream() .sorted( @@ -172,10 +178,18 @@ return map == null ? Collections.emptyList() : map.keySet(); } + public GraphLens getGraphLens() { + return graphLens; + } + public NamingLens getNamingLens() { return namingLens; } + public LensCodeRewriterUtils getLensCodeRewriter() { + return lensCodeRewriter; + } + public Collection<DexMethod> getMethods() { return keysOrEmpty(methods); }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java new file mode 100644 index 0000000..93e42d1 --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
@@ -0,0 +1,24 @@ +// 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 ProgramDexCode { + + private final DexCode code; + private final ProgramMethod method; + + public ProgramDexCode(DexCode code, ProgramMethod method) { + this.code = code; + this.method = method; + } + + public DexCode getCode() { + return code; + } + + public ProgramMethod getMethod() { + return method; + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java index 3069f4e..7721c67 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramField.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.graph; +import com.android.tools.r8.dex.IndexedItemCollection; + public class ProgramField extends DexClassAndField implements ProgramMember<DexEncodedField, DexField> { @@ -11,6 +13,15 @@ super(holder, field); } + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getReference().collectIndexedItems(indexedItems); + DexEncodedField definition = getDefinition(); + definition.annotations().collectIndexedItems(indexedItems); + if (definition.isStatic() && definition.hasExplicitStaticValue()) { + definition.getStaticValue().collectIndexedItems(indexedItems); + } + } + public boolean isStructurallyEqualTo(ProgramField other) { return getDefinition() == other.getDefinition() && getHolder() == other.getHolder(); }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java index e69ade7..a1fe5c7 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -3,9 +3,11 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.graph; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.NumberGenerator; import com.android.tools.r8.ir.code.Position; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.ir.conversion.MethodProcessor; import com.android.tools.r8.logging.Log; import com.android.tools.r8.origin.Origin; @@ -35,6 +37,20 @@ context, this, appView, valueNumberGenerator, callerPosition, origin, methodProcessor); } + public void collectIndexedItems( + IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) { + DexEncodedMethod definition = getDefinition(); + assert !definition.isObsolete(); + assert !definition.hasCode() || definition.getCode().isDexCode(); + getReference().collectIndexedItems(indexedItems); + Code code = definition.getCode(); + if (code != null && code.isDexCode()) { + code.asDexCode().collectIndexedItems(indexedItems, this, graphLens, rewriter); + } + definition.annotations().collectIndexedItems(indexedItems); + definition.parameterAnnotationsList.collectIndexedItems(indexedItems); + } + public boolean isStructurallyEqualTo(ProgramMethod other) { return getDefinition() == other.getDefinition() && getHolder() == other.getHolder(); }
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 3316b64..82b02c4 100644 --- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java +++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -177,6 +177,12 @@ return resolvedMethod; } + public ProgramMethod getResolvedProgramMethod() { + return resolvedHolder.isProgramClass() + ? new ProgramMethod(resolvedHolder.asProgramClass(), resolvedMethod) + : null; + } + public DexClassAndMethod getResolutionPair() { return DexClassAndMethod.create(resolvedHolder, resolvedMethod); }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java index 51ef31e..1f751ad 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -17,13 +17,16 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.FieldAccessFlags; import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier; import com.android.tools.r8.utils.MethodSignatureEquivalence; import com.google.common.base.Equivalence.Wrapper; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import java.util.ArrayList; import java.util.Collection; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -31,8 +34,10 @@ * class {@link ClassMerger#target}. While performing merging, this class tracks which methods have * been moved, as well as which fields have been remapped in the {@link ClassMerger#lensBuilder}. */ -class ClassMerger { - private final AppView<?> appView; +public class ClassMerger { + public static final String CLASS_ID_FIELD_NAME = "$r8$classId"; + + private final AppView<AppInfoWithLiveness> appView; private final DexProgramClass target; private final Collection<DexProgramClass> toMergeGroup; private final DexItemFactory dexItemFactory; @@ -40,41 +45,33 @@ private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder; private final Reference2IntMap<DexType> classIdentifiers = new Reference2IntOpenHashMap<>(); - private final Map<DexProto, ConstructorMerger.Builder> constructorMergers; + private final Collection<VirtualMethodMerger> virtualMethodMergers; + private final Collection<ConstructorMerger> constructorMergers; private final DexField classIdField; - ClassMerger( - AppView<?> appView, + private ClassMerger( + AppView<AppInfoWithLiveness> appView, HorizontalClassMergerGraphLens.Builder lensBuilder, FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, DexProgramClass target, - Collection<DexProgramClass> toMergeGroup) { + Collection<DexProgramClass> toMergeGroup, + DexField classIdField, + Collection<VirtualMethodMerger> virtualMethodMergers, + Collection<ConstructorMerger> constructorMergers) { this.appView = appView; this.lensBuilder = lensBuilder; this.fieldAccessChangesBuilder = fieldAccessChangesBuilder; this.target = target; this.toMergeGroup = toMergeGroup; + this.classIdField = classIdField; + this.virtualMethodMergers = virtualMethodMergers; + this.constructorMergers = constructorMergers; - this.constructorMergers = new IdentityHashMap<>(); this.dexItemFactory = appView.dexItemFactory(); - // TODO(b/165498187): ensure the name for the field is fresh - classIdField = dexItemFactory.createField(target.type, dexItemFactory.intType, "$r8$classId"); - buildClassIdentifierMap(); } - Wrapper<DexMethod> bySignature(DexMethod method) { - return MethodSignatureEquivalence.get().wrap(method); - } - - void addConstructor(DexEncodedMethod method) { - assert method.isInstanceInitializer(); - constructorMergers - .computeIfAbsent(method.proto(), ignore -> new ConstructorMerger.Builder()) - .add(method); - } - void buildClassIdentifierMap() { classIdentifiers.put(target.type, 0); for (DexProgramClass toMerge : toMergeGroup) { @@ -83,21 +80,16 @@ } void merge(DexProgramClass toMerge) { - toMerge.forEachProgramMethod( - programMethod -> { - DexEncodedMethod method = programMethod.getDefinition(); - assert !method.isClassInitializer(); + toMerge.forEachProgramDirectMethod( + method -> { + DexEncodedMethod definition = method.getDefinition(); + assert !definition.isClassInitializer(); - if (method.isInstanceInitializer()) { - addConstructor(method); - } else { - // TODO(b/166427795): Ensure that overriding relationships are not changed. - assert method.isVirtualMethod(); - - DexMethod newMethod = renameMethod(programMethod); - // TODO(b/165000217): Add all methods to `target` in one go using addVirtualMethods().; - target.addVirtualMethod(method.toTypeSubstitutedMethod(newMethod)); - lensBuilder.moveMethod(method.method, newMethod); + if (!definition.isInstanceInitializer()) { + DexMethod newMethod = renameMethod(method); + // TODO(b/165000217): Add all methods to `target` in one go using addDirectMethods(). + target.addDirectMethod(definition.toTypeSubstitutedMethod(newMethod)); + lensBuilder.moveMethod(definition.getReference(), newMethod); } }); @@ -123,24 +115,15 @@ } void mergeConstructors() { - for (ConstructorMerger.Builder builder : constructorMergers.values()) { - ConstructorMerger constructorMerger = builder.build(appView, target, classIdField); - constructorMerger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers); + for (ConstructorMerger merger : constructorMergers) { + merger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers); } } - /** - * To ensure constructor merging happens correctly, add all of the target constructors methods to - * constructor mergers. - */ - void addTargetConstructors() { - target.forEachProgramDirectMethod( - programMethod -> { - DexEncodedMethod method = programMethod.getDefinition(); - if (method.isInstanceInitializer()) { - addConstructor(method); - } - }); + void mergeVirtualMethods() { + for (VirtualMethodMerger merger : virtualMethodMergers) { + merger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers); + } } void appendClassIdField() { @@ -155,13 +138,102 @@ } public void mergeGroup() { - addTargetConstructors(); appendClassIdField(); for (DexProgramClass clazz : toMergeGroup) { merge(clazz); + lensBuilder.mapType(clazz.type, target.type); } mergeConstructors(); + mergeVirtualMethods(); + } + + public static class Builder { + private final DexProgramClass target; + private final Collection<DexProgramClass> toMergeGroup = new ArrayList<>(); + private final Map<DexProto, ConstructorMerger.Builder> constructorMergerBuilders = + new IdentityHashMap<>(); + private final Map<Wrapper<DexMethod>, VirtualMethodMerger.Builder> virtualMethodMergerBuilders = + new LinkedHashMap<>(); + + public Builder(DexProgramClass target) { + this.target = target; + setupForMethodMerging(target); + } + + public Builder mergeClass(DexProgramClass toMerge) { + setupForMethodMerging(toMerge); + toMergeGroup.add(toMerge); + return this; + } + + public Builder addClassesToMerge(Collection<DexProgramClass> toMerge) { + toMerge.forEach(this::mergeClass); + return this; + } + + void setupForMethodMerging(DexProgramClass toMerge) { + toMerge.forEachProgramDirectMethod( + method -> { + DexEncodedMethod definition = method.getDefinition(); + assert !definition.isClassInitializer(); + + if (definition.isInstanceInitializer()) { + addConstructor(method); + } + }); + + toMerge.forEachProgramVirtualMethod(this::addVirtualMethod); + } + + void addConstructor(ProgramMethod method) { + assert method.getDefinition().isInstanceInitializer(); + constructorMergerBuilders + .computeIfAbsent( + method.getDefinition().getProto(), ignore -> new ConstructorMerger.Builder()) + .add(method.getDefinition()); + } + + void addVirtualMethod(ProgramMethod method) { + assert method.getDefinition().isNonPrivateVirtualMethod(); + virtualMethodMergerBuilders + .computeIfAbsent( + MethodSignatureEquivalence.get().wrap(method.getReference()), + ignore -> new VirtualMethodMerger.Builder()) + .add(method); + } + + public ClassMerger build( + AppView<AppInfoWithLiveness> appView, + HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) { + DexItemFactory dexItemFactory = appView.dexItemFactory(); + // TODO(b/165498187): ensure the name for the field is fresh + DexField classIdField = + dexItemFactory.createField(target.type, dexItemFactory.intType, CLASS_ID_FIELD_NAME); + + Collection<VirtualMethodMerger> virtualMethodMergers = + new ArrayList<>(virtualMethodMergerBuilders.size()); + for (VirtualMethodMerger.Builder builder : virtualMethodMergerBuilders.values()) { + virtualMethodMergers.add(builder.build(appView, target, classIdField)); + } + + Collection<ConstructorMerger> constructorMergers = + new ArrayList<>(constructorMergerBuilders.size()); + for (ConstructorMerger.Builder builder : constructorMergerBuilders.values()) { + constructorMergers.add(builder.build(appView, target, classIdField)); + } + + return new ClassMerger( + appView, + lensBuilder, + fieldAccessChangesBuilder, + target, + toMergeGroup, + classIdField, + virtualMethodMergers, + constructorMergers); + } } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java index 76f4814..cd2d31c 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
@@ -107,7 +107,8 @@ private MethodAccessFlags getAccessFlags() { // TODO(b/164998929): ensure this behaviour is correct, should probably calculate upper bound - return MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, true); + return MethodAccessFlags.fromSharedAccessFlags( + Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, true); } /** Synthesize a new method which selects the constructor based on a parameter type. */
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java index f7ac858..a938abb 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -6,7 +6,6 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.graph.DexType; import com.android.tools.r8.horizontalclassmerging.policies.NoFields; import com.android.tools.r8.horizontalclassmerging.policies.NoInterfaces; import com.android.tools.r8.horizontalclassmerging.policies.NoInternalUtilityClasses; @@ -17,12 +16,11 @@ import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.ClassMergingEnqueuerExtension; import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier; -import com.android.tools.r8.shaking.MainDexClasses; +import com.android.tools.r8.shaking.MainDexTracingResult; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -32,7 +30,7 @@ public HorizontalClassMerger( AppView<AppInfoWithLiveness> appView, - MainDexClasses mainDexClasses, + MainDexTracingResult mainDexClasses, ClassMergingEnqueuerExtension classMergingEnqueuerExtension) { this.appView = appView; @@ -52,6 +50,7 @@ this.policyExecutor = new SimplePolicyExecutor(policies); } + // TODO(b/165577835): replace Collection<DexProgramClass> with MergeGroup public HorizontalClassMergerGraphLens run() { Map<FieldMultiset, Collection<DexProgramClass>> classes = new HashMap<>(); @@ -63,23 +62,32 @@ // Run the policies on all collected classes to produce a final grouping. Collection<Collection<DexProgramClass>> groups = policyExecutor.run(classes.values()); - return createLens(groups); - } - - // TODO(b/165577835): replace Collection<DexProgramClass> with MergeGroup - /** - * Merges all class groups using {@link ClassMerger}. Then fix all references to merged classes - * using the {@link TreeFixer}. Constructs a graph lens containing all changes while performing - * merging. - */ - private HorizontalClassMergerGraphLens createLens( - Collection<Collection<DexProgramClass>> groups) { - Map<DexType, DexType> mergedClasses = new IdentityHashMap<>(); HorizontalClassMergerGraphLens.Builder lensBuilder = new HorizontalClassMergerGraphLens.Builder(); FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder = new FieldAccessInfoCollectionModifier.Builder(); + // Set up a class merger for each group. + Collection<ClassMerger> classMergers = + initializeClassMergers(lensBuilder, fieldAccessChangesBuilder, groups); + + // Merge the classes. + applyClassMergers(classMergers); + + // Generate the class lens. + return createLens(lensBuilder, fieldAccessChangesBuilder); + } + + /** + * Prepare horizontal class merging by determining which virtual methods and constructors need to + * be merged and how the merging should be performed. + */ + private Collection<ClassMerger> initializeClassMergers( + HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, + Collection<Collection<DexProgramClass>> groups) { + Collection<ClassMerger> classMergers = new ArrayList<>(); + // TODO(b/166577694): Replace Collection<DexProgramClass> with MergeGroup for (Collection<DexProgramClass> group : groups) { assert !group.isEmpty(); @@ -87,18 +95,33 @@ DexProgramClass target = group.stream().findFirst().get(); group.remove(target); - for (DexProgramClass clazz : group) { - mergedClasses.put(clazz.type, target.type); - } - ClassMerger merger = - new ClassMerger(appView, lensBuilder, fieldAccessChangesBuilder, target, group); - merger.mergeGroup(); + new ClassMerger.Builder(target) + .addClassesToMerge(group) + .build(appView, lensBuilder, fieldAccessChangesBuilder); + classMergers.add(merger); } + return classMergers; + } + + /** Merges all class groups using {@link ClassMerger}. */ + private void applyClassMergers(Collection<ClassMerger> classMergers) { + for (ClassMerger merger : classMergers) { + merger.mergeGroup(); + } + } + + /** + * Fix all references to merged classes using the {@link TreeFixer}. Construct a graph lens + * containing all changes performed by horizontal class merging. + */ + private HorizontalClassMergerGraphLens createLens( + HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) { + HorizontalClassMergerGraphLens lens = - new TreeFixer(appView, lensBuilder, fieldAccessChangesBuilder, mergedClasses) - .fixupTypeReferences(); + new TreeFixer(appView, lensBuilder, fieldAccessChangesBuilder).fixupTypeReferences(); return lens; } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java index 4389282..482ade5 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -83,10 +83,10 @@ } public static class Builder { - protected final BiMap<DexField, DexField> fieldMap = HashBiMap.create(); - protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>(); - protected final Map<DexMethod, Set<DexMethod>> completeInverseMethodMap = - new IdentityHashMap<>(); + private final Map<DexType, DexType> typeMap = new IdentityHashMap<>(); + private final BiMap<DexField, DexField> fieldMap = HashBiMap.create(); + private final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>(); + private final Map<DexMethod, Set<DexMethod>> completeInverseMethodMap = new IdentityHashMap<>(); private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create(); private final Map<DexMethod, DexMethod> extraOriginalMethodSignatures = new IdentityHashMap<>(); @@ -95,16 +95,15 @@ Builder() {} - public HorizontalClassMergerGraphLens build( - AppView<?> appView, Map<DexType, DexType> mergedClasses) { - if (mergedClasses.isEmpty()) { + public HorizontalClassMergerGraphLens build(AppView<?> appView) { + if (typeMap.isEmpty()) { return null; } else { BiMap<DexField, DexField> originalFieldSignatures = fieldMap.inverse(); return new HorizontalClassMergerGraphLens( appView, constructorIds, - mergedClasses, + typeMap, fieldMap, methodMap, originalFieldSignatures, @@ -114,6 +113,15 @@ } } + public DexType lookupType(DexType type) { + return typeMap.getOrDefault(type, type); + } + + public Builder mapType(DexType from, DexType to) { + typeMap.put(from, to); + return this; + } + /** Bidirectional mapping from one method to another. */ public Builder moveMethod(DexMethod from, DexMethod to) { mapMethod(from, to);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java index 261e8d2..1ce2ee4 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java
@@ -10,6 +10,13 @@ public abstract class MultiClassPolicy extends Policy { /** + * Remove all groups containing no or only a single class, as there is no point in merging these. + */ + protected void removeTrivialGroups(Collection<Collection<DexProgramClass>> groups) { + groups.removeIf(group -> group.size() < 2); + } + + /** * Apply the multi class policy to a group of program classes. * * @param group This is a group of program classes which can currently still be merged.
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java index 3e6254c..9ec4e5f 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
@@ -32,7 +32,7 @@ j.remove(); } } - if (group.isEmpty()) { + if (group.size() < 2) { i.remove(); } } @@ -56,6 +56,9 @@ } else if (policy instanceof MultiClassPolicy) { groups = applyMultiClassPolicy((MultiClassPolicy) policy, groups); } + + // Any policy should not return any trivial groups. + assert groups.stream().allMatch(group -> group.size() >= 2); } return groups;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java index 7d0d5c0..087c6ef 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -23,12 +23,10 @@ /** * The tree fixer traverses all program classes and finds and fixes references to old classes which - * have been remapped to new classes by the class merger (stored in {@link - * TreeFixer#mergedClasses}). While doing so, all updated changes are tracked in {@link - * TreeFixer#lensBuilder}. + * have been remapped to new classes by the class merger. While doing so, all updated changes are + * tracked in {@link TreeFixer#lensBuilder}. */ class TreeFixer { - private final Map<DexType, DexType> mergedClasses; private final Map<DexProto, DexProto> protoFixupCache = new IdentityHashMap<>(); private final HorizontalClassMergerGraphLens.Builder lensBuilder; private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder; @@ -37,9 +35,7 @@ public TreeFixer( AppView<AppInfoWithLiveness> appView, HorizontalClassMergerGraphLens.Builder lensBuilder, - FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, - Map<DexType, DexType> mergedClasses) { - this.mergedClasses = mergedClasses; + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) { this.lensBuilder = lensBuilder; this.fieldAccessChangesBuilder = fieldAccessChangesBuilder; this.appView = appView; @@ -48,11 +44,12 @@ HorizontalClassMergerGraphLens fixupTypeReferences() { // Globally substitute merged class types in protos and holders. for (DexProgramClass clazz : appView.appInfo().classes()) { + clazz.superType = lensBuilder.lookupType(clazz.superType); clazz.getMethodCollection().replaceMethods(this::fixupMethod); fixupFields(clazz.staticFields(), clazz::setStaticField); fixupFields(clazz.instanceFields(), clazz::setInstanceField); } - HorizontalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses); + HorizontalClassMergerGraphLens lens = lensBuilder.build(appView); fieldAccessChangesBuilder.build(this::fixupMethod).modify(appView); @@ -133,8 +130,10 @@ return type.replaceBaseType(fixed, appView.dexItemFactory()); } if (type.isClassType()) { - while (mergedClasses.containsKey(type)) { - type = mergedClasses.get(type); + while (true) { + DexType mapped = lensBuilder.lookupType(type); + if (mapped == type) break; + type = mapped; } } return type;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java new file mode 100644 index 0000000..494e383 --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java
@@ -0,0 +1,163 @@ +// 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.horizontalclassmerging; + +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.ir.code.Invoke.Type; +import com.android.tools.r8.ir.code.Position; +import com.android.tools.r8.ir.code.Value; +import com.android.tools.r8.ir.code.ValueType; +import com.android.tools.r8.ir.conversion.IRBuilder; +import com.android.tools.r8.ir.synthetic.SyntheticSourceCode; +import com.android.tools.r8.utils.IntBox; +import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry; +import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap; +import java.util.ArrayList; +import java.util.List; + +/** + * Assuming a method signature <code> + * void method([args]); + * </code>. This class generates code depending on which of the following cases it matches. + * + * <p>If the method does not override a method and is implemented by many (e.g. 2) classes: + * + * <pre> + * void method([args]) { + * switch (classId) { + * case 0: + * return method$1([args]); + * default: + * return method$2([args]); + * } + * } + * </pre> + * + * <p>If the method overrides a method and is implemented by any number of classes: + * + * <pre> + * void method([args]) { + * switch (classId) { + * case 0: + * return method$1([args]); + * // ... further cases ... + * default: + * return super.method$1([args]); + * } + * } + * </pre> + */ +public class VirtualMethodEntryPoint extends SyntheticSourceCode { + private final Int2ReferenceSortedMap<DexMethod> mappedMethods; + private final DexField classIdField; + private final DexMethod superMethod; + + public VirtualMethodEntryPoint( + Int2ReferenceSortedMap<DexMethod> mappedMethods, + DexField classIdField, + DexMethod superMethod, + DexMethod newMethod, + Position callerPosition, + DexMethod originalMethod) { + super(newMethod.holder, newMethod, callerPosition, originalMethod); + + assert classIdField != null; + + this.mappedMethods = mappedMethods; + this.classIdField = classIdField; + this.superMethod = superMethod; + } + + void addInvokeDirect(DexMethod method) { + add( + builder -> { + List<Value> arguments = new ArrayList<>(method.getArity() + 1); + arguments.add(builder.getReceiverValue()); + if (builder.getArgumentValues() != null) { + arguments.addAll(builder.getArgumentValues()); + } + builder.addInvoke(Type.DIRECT, method, method.proto, arguments, false); + }); + } + + void addInvokeSuper() { + assert superMethod != null; + + add( + builder -> { + List<Value> arguments = new ArrayList<>(method.getArity() + 1); + arguments.add(builder.getReceiverValue()); + if (builder.getArgumentValues() != null) { + arguments.addAll(builder.getArgumentValues()); + } + builder.addInvoke(Type.SUPER, superMethod, superMethod.proto, arguments, false); + }); + } + + void handleReturn(int retRegister) { + if (proto.returnType.isVoidType()) { + add(IRBuilder::addReturn, endsBlock); + } else { + add(builder -> builder.addMoveResult(retRegister)); + add(builder -> builder.addReturn(retRegister), endsBlock); + } + } + + @Override + protected void prepareInstructions() { + int casesCount = mappedMethods.size(); + + // If there is no super method, use one of the cases as a fallthrough case. + if (superMethod == null) { + casesCount--; + } + + assert casesCount > 0; + + // Return value register if needed. + int returnRegister = + !proto.returnType.isVoidType() ? nextRegister(ValueType.fromDexType(proto.returnType)) : -1; + + int[] keys = new int[casesCount]; + int[] offsets = new int[casesCount]; + IntBox fallthrough = new IntBox(); + + // Fetch the class id from the class id field. + int idRegister = nextRegister(ValueType.INT); + add(builder -> builder.addInstanceGet(idRegister, getReceiverRegister(), classIdField)); + + int switchIndex = lastInstructionIndex(); + add( + builder -> builder.addSwitch(idRegister, keys, fallthrough.get(), offsets), + builder -> endsSwitch(builder, switchIndex, fallthrough.get(), offsets)); + + int index = 0; + for (Entry<DexMethod> entry : mappedMethods.int2ReferenceEntrySet()) { + int classId = entry.getIntKey(); + DexMethod mappedMethod = entry.getValue(); + + // If there is no super method, then use the last case as the default case. + if (index >= casesCount) { + fallthrough.set(nextInstructionIndex()); + } else { + keys[index] = classId; + offsets[index] = nextInstructionIndex(); + } + + addInvokeDirect(mappedMethod); + handleReturn(returnRegister); + + index++; + } + + // If the super class implements this method, then the fallthrough case should execute it. + if (superMethod != null) { + fallthrough.set(nextInstructionIndex()); + addInvokeSuper(); + handleReturn(returnRegister); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java new file mode 100644 index 0000000..d6690a9 --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
@@ -0,0 +1,43 @@ +// 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.horizontalclassmerging; + +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.UseRegistry; +import com.android.tools.r8.ir.synthetic.SynthesizedCode; +import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap; +import java.util.function.Consumer; + +public class VirtualMethodEntryPointSynthesizedCode extends SynthesizedCode { + private final Int2ReferenceSortedMap<DexMethod> mappedMethods; + private final DexField classIdField; + + public VirtualMethodEntryPointSynthesizedCode( + Int2ReferenceSortedMap<DexMethod> mappedMethods, + DexField classIdField, + DexMethod superMethod, + DexMethod method, + DexMethod originalMethod) { + super( + position -> + new VirtualMethodEntryPoint( + mappedMethods, classIdField, superMethod, method, position, originalMethod)); + + this.mappedMethods = mappedMethods; + this.classIdField = classIdField; + } + + @Override + public Consumer<UseRegistry> getRegistryCallback() { + return this::registerReachableDefinitions; + } + + private void registerReachableDefinitions(UseRegistry registry) { + for (DexMethod mappedMethod : mappedMethods.values()) { + registry.registerInvokeDirect(mappedMethod); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java new file mode 100644 index 0000000..5e20c04f --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -0,0 +1,185 @@ +// 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.horizontalclassmerging; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexAnnotationSet; +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.MethodAccessFlags; +import com.android.tools.r8.graph.ParameterAnnotationsList; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult; +import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode; +import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier; +import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import java.util.ArrayList; +import java.util.Collection; + +public class VirtualMethodMerger { + private final DexProgramClass target; + private final DexItemFactory dexItemFactory; + private final Collection<ProgramMethod> methods; + private final DexField classIdField; + private final AppView<AppInfoWithLiveness> appView; + private final DexMethod superMethod; + + public VirtualMethodMerger( + AppView<AppInfoWithLiveness> appView, + DexProgramClass target, + Collection<ProgramMethod> methods, + DexField classIdField, + DexMethod superMethod) { + this.dexItemFactory = appView.dexItemFactory(); + this.target = target; + this.classIdField = classIdField; + this.methods = methods; + this.appView = appView; + this.superMethod = superMethod; + } + + public static class Builder { + private final Collection<ProgramMethod> methods = new ArrayList<>(); + + public Builder add(ProgramMethod constructor) { + methods.add(constructor); + return this; + } + + /** Get the super method handle if this method overrides a parent method. */ + private DexMethod superMethod(AppView<AppInfoWithLiveness> appView, DexProgramClass target) { + // TODO(b/167981556): Correctly detect super methods defined on interfaces. + DexMethod template = methods.iterator().next().getReference(); + SingleResolutionResult resolutionResult = + appView + .withLiveness() + .appInfo() + .resolveMethodOnClass(template, target.superType) + .asSingleResolution(); + if (resolutionResult == null) { + return null; + } + return resolutionResult.getResolvedMethod().method; + } + + public VirtualMethodMerger build( + AppView<AppInfoWithLiveness> appView, DexProgramClass target, DexField classIdField) { + DexMethod superMethod = superMethod(appView, target); + return new VirtualMethodMerger(appView, target, methods, classIdField, superMethod); + } + } + + private DexMethod moveMethod(ProgramMethod oldMethod) { + DexMethod oldMethodReference = oldMethod.getReference(); + DexMethod method = + dexItemFactory.createFreshMethodName( + oldMethodReference.name.toSourceString(), + oldMethod.getHolderType(), + oldMethodReference.proto, + target.type, + tryMethod -> target.lookupMethod(tryMethod) == null); + + if (oldMethod.getHolderType() == target.type) { + target.removeMethod(oldMethod.getReference()); + } + + DexEncodedMethod encodedMethod = oldMethod.getDefinition().toTypeSubstitutedMethod(method); + MethodAccessFlags flags = encodedMethod.accessFlags; + flags.unsetProtected(); + flags.unsetPublic(); + flags.setPrivate(); + target.addDirectMethod(encodedMethod); + + return encodedMethod.method; + } + + private MethodAccessFlags getAccessFlags() { + // TODO(b/164998929): ensure this behaviour is correct, should probably calculate upper bound + return methods.iterator().next().getDefinition().getAccessFlags(); + } + + + /** + * If there is only a single method that does not override anything then it is safe to just move + * it to the target type if it is not already in it. + */ + public void mergeTrivial(HorizontalClassMergerGraphLens.Builder lensBuilder) { + ProgramMethod method = methods.iterator().next(); + + if (method.getHolderType() != target.type) { + // If the method is not in the target type, move it and record it in the lens. + DexEncodedMethod newMethod = + method.getDefinition().toRenamedHolderMethod(target.type, dexItemFactory); + target.addVirtualMethod(newMethod); + lensBuilder.moveMethod(method.getReference(), newMethod.getReference()); + } + } + + public void merge( + HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, + Reference2IntMap classIdentifiers) { + + assert !methods.isEmpty(); + + // Handle trivial merges. + if (superMethod == null && methods.size() == 1) { + mergeTrivial(lensBuilder); + return; + } + + Int2ReferenceSortedMap<DexMethod> classIdToMethodMap = new Int2ReferenceAVLTreeMap<>(); + + int classFileVersion = -1; + for (ProgramMethod method : methods) { + if (method.getDefinition().hasClassFileVersion()) { + classFileVersion = + Integer.max(classFileVersion, method.getDefinition().getClassFileVersion()); + } + DexMethod newMethod = moveMethod(method); + lensBuilder.recordOriginalSignature(method.getReference(), newMethod); + classIdToMethodMap.put(classIdentifiers.getInt(method.getHolderType()), newMethod); + } + + // Use the first of the original methods as the original method for the merged constructor. + DexMethod originalMethodReference = methods.iterator().next().getReference(); + + DexMethod newMethodReference = + dexItemFactory.createMethod( + target.type, originalMethodReference.proto, originalMethodReference.name); + AbstractSynthesizedCode synthesizedCode = + new VirtualMethodEntryPointSynthesizedCode( + classIdToMethodMap, + classIdField, + superMethod, + newMethodReference, + originalMethodReference); + DexEncodedMethod newMethod = + new DexEncodedMethod( + newMethodReference, + getAccessFlags(), + DexAnnotationSet.empty(), + ParameterAnnotationsList.empty(), + synthesizedCode, + classFileVersion, + true); + + // Map each old method to the newly synthesized method in the graph lens. + for (ProgramMethod oldMethod : methods) { + lensBuilder.mapMethod(oldMethod.getReference(), newMethodReference); + } + lensBuilder.recordExtraOriginalSignature(originalMethodReference, newMethodReference); + + target.addVirtualMethod(newMethod); + + fieldAccessChangesBuilder.fieldReadByMethod(classIdField, newMethod.method); + } +}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java index 4e1987e..5b274d1 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java
@@ -22,6 +22,7 @@ .computeIfAbsent(clazz.superType, ignore -> new LinkedList<DexProgramClass>()) .add(clazz); } + removeTrivialGroups(groups.values()); return groups.values(); } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java index c2ffda0..41a0192 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -12,14 +12,30 @@ public abstract boolean isNonTrivial(); + public boolean isSingleBoolean() { + return false; + } + public boolean isBottom() { return false; } - public boolean isZero() { + public boolean isFalse() { return false; } + public boolean isTrue() { + return false; + } + + public final boolean isNull() { + return isFalse(); + } + + public final boolean isZero() { + return isFalse(); + } + /** * Returns true if this abstract value represents a single concrete value (i.e., the * concretization of this abstract value has size 1).
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 98a7fa4..76e6ac8 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
@@ -27,11 +27,21 @@ } @Override - public boolean isZero() { + public boolean isSingleBoolean() { + return isFalse() || isTrue(); + } + + @Override + public boolean isFalse() { return value == 0; } @Override + public boolean isTrue() { + return value == 1; + } + + @Override public boolean isSingleNumberValue() { return true; } @@ -46,14 +56,26 @@ return value != 0; } - public long getValue() { - return value; + public double getDoubleValue() { + return Double.longBitsToDouble(value); + } + + public float getFloatValue() { + return Float.intBitsToFloat((int) value); } public int getIntValue() { return (int) value; } + public long getLongValue() { + return value; + } + + public long getValue() { + return value; + } + @Override public boolean equals(Object o) { return this == o;
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 3d7ae52..23808f4 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
@@ -121,4 +121,10 @@ public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) { return false; } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(super.toString()); + return builder.append("; ").append(type.toSourceString()).toString(); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java index 1c19488..0e40a2a 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java +++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -3,6 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.code; +import com.android.tools.r8.code.InvokeCustomRange; +import com.android.tools.r8.code.InvokeDirectRange; +import com.android.tools.r8.code.InvokeInterfaceRange; +import com.android.tools.r8.code.InvokePolymorphicRange; +import com.android.tools.r8.code.InvokeStaticRange; +import com.android.tools.r8.code.InvokeSuperRange; +import com.android.tools.r8.code.InvokeVirtualRange; import com.android.tools.r8.code.MoveResult; import com.android.tools.r8.code.MoveResultObject; import com.android.tools.r8.code.MoveResultWide; @@ -20,19 +27,60 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import java.util.List; import java.util.Set; +import org.objectweb.asm.Opcodes; public abstract class Invoke extends Instruction { + private static final int NO_SUCH_DEX_INSTRUCTION = -1; + public enum Type { - DIRECT, - INTERFACE, - STATIC, - SUPER, - VIRTUAL, - NEW_ARRAY, - MULTI_NEW_ARRAY, - CUSTOM, - POLYMORPHIC; + DIRECT(com.android.tools.r8.code.InvokeDirect.OPCODE, InvokeDirectRange.OPCODE), + INTERFACE(com.android.tools.r8.code.InvokeInterface.OPCODE, InvokeInterfaceRange.OPCODE), + STATIC(com.android.tools.r8.code.InvokeStatic.OPCODE, InvokeStaticRange.OPCODE), + SUPER(com.android.tools.r8.code.InvokeSuper.OPCODE, InvokeSuperRange.OPCODE), + VIRTUAL(com.android.tools.r8.code.InvokeVirtual.OPCODE, InvokeVirtualRange.OPCODE), + NEW_ARRAY(com.android.tools.r8.code.NewArray.OPCODE, NO_SUCH_DEX_INSTRUCTION), + MULTI_NEW_ARRAY(NO_SUCH_DEX_INSTRUCTION, NO_SUCH_DEX_INSTRUCTION), + CUSTOM(com.android.tools.r8.code.InvokeCustom.OPCODE, InvokeCustomRange.OPCODE), + POLYMORPHIC(com.android.tools.r8.code.InvokePolymorphic.OPCODE, InvokePolymorphicRange.OPCODE); + + private final int dexOpcode; + private final int dexOpcodeRange; + + Type(int dexOpcode, int dexOpcodeRange) { + this.dexOpcode = dexOpcode; + this.dexOpcodeRange = dexOpcodeRange; + } + + public int getCfOpcode() { + switch (this) { + case DIRECT: + return Opcodes.INVOKESPECIAL; + case INTERFACE: + return Opcodes.INVOKEINTERFACE; + case STATIC: + return Opcodes.INVOKESTATIC; + case SUPER: + return Opcodes.INVOKESPECIAL; + case VIRTUAL: + return Opcodes.INVOKEVIRTUAL; + case NEW_ARRAY: + case MULTI_NEW_ARRAY: + case POLYMORPHIC: + default: + throw new Unreachable(); + } + } + + public int getDexOpcode() { + assert dexOpcode >= 0; + return dexOpcode; + } + + public int getDexOpcodeRange() { + assert dexOpcodeRange >= 0; + return dexOpcodeRange; + } public MethodHandleType toMethodHandle(DexMethod targetMethod) { switch (this) {
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 52ab07a..f5a51c8 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
@@ -273,7 +273,7 @@ } FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(encodedField.field); - if (fieldAccessInfo != null) { + if (fieldAccessInfo != null && fieldAccessInfo.hasKnownWriteContexts()) { if (fieldAccessInfo.getNumberOfWriteContexts() == 1) { fieldAccessInfo.forEachWriteContext(this::addFieldReadEdge); }
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 4c10624..5107d27 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
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.conversion; +import static com.android.tools.r8.graph.DexAnnotation.readAnnotationSynthesizedClassMap; import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources; import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources; @@ -90,6 +91,7 @@ import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis; import com.android.tools.r8.shaking.MainDexClasses; +import com.android.tools.r8.shaking.MainDexTracingResult; import com.android.tools.r8.utils.Action; import com.android.tools.r8.utils.CfgPrinter; import com.android.tools.r8.utils.DescriptorUtils; @@ -190,7 +192,7 @@ * (i.e., whether we are running R8). See {@link AppView#enableWholeProgramOptimizations()}. */ public IRConverter( - AppView<?> appView, Timing timing, CfgPrinter printer, MainDexClasses mainDexClasses) { + AppView<?> appView, Timing timing, CfgPrinter printer, MainDexTracingResult mainDexClasses) { assert appView.appInfo().hasLiveness() || appView.graphLens().isIdentityLens(); assert appView.options() != null; assert appView.options().programConsumer != null; @@ -309,7 +311,7 @@ this.memberValuePropagation = options.enableValuePropagation ? new MemberValuePropagation(appViewWithLiveness) : null; this.methodOptimizationInfoCollector = - new MethodOptimizationInfoCollector(appViewWithLiveness); + new MethodOptimizationInfoCollector(appViewWithLiveness, this); if (options.isMinifying()) { this.identifierNameStringMarker = new IdentifierNameStringMarker(appViewWithLiveness); } else { @@ -364,16 +366,16 @@ /** Create an IR converter for processing methods with full program optimization disabled. */ public IRConverter(AppView<?> appView, Timing timing) { - this(appView, timing, null, MainDexClasses.NONE); + this(appView, timing, null, MainDexTracingResult.NONE); } /** Create an IR converter for processing methods with full program optimization disabled. */ public IRConverter(AppView<?> appView, Timing timing, CfgPrinter printer) { - this(appView, timing, printer, MainDexClasses.NONE); + this(appView, timing, printer, MainDexTracingResult.NONE); } public IRConverter(AppInfo appInfo, Timing timing, CfgPrinter printer) { - this(AppView.createForD8(appInfo), timing, printer, MainDexClasses.NONE); + this(AppView.createForD8(appInfo), timing, printer, MainDexTracingResult.NONE); } private boolean enableTwrCloseResourceDesugaring() { @@ -493,42 +495,54 @@ processCovariantReturnTypeAnnotations(builder); generateDesugaredLibraryAPIWrappers(builder, executor); - handleSynthesizedClassMapping(builder); + handleSynthesizedClassMapping(appView, builder); timing.end(); DexApplication app = builder.build(); - appView.setAppInfo(new AppInfo(app, appView.appInfo().getSyntheticItems().commit(app))); + appView.setAppInfo( + new AppInfo( + app, + appView.appInfo().getMainDexClasses(), + appView.appInfo().getSyntheticItems().commit(app))); } - private void handleSynthesizedClassMapping(Builder<?> builder) { + private void handleSynthesizedClassMapping(AppView<?> appView, Builder<?> builder) { if (options.intermediate) { updateSynthesizedClassMapping(builder); } - updateMainDexListWithSynthesizedClassMap(builder); + updateMainDexListWithSynthesizedClassMap(appView, builder); if (!options.intermediate) { clearSynthesizedClassMapping(builder); } } - private void updateMainDexListWithSynthesizedClassMap(Builder<?> builder) { - Set<DexType> inputMainDexList = builder.getMainDexList(); - if (!inputMainDexList.isEmpty()) { - Map<DexType, DexProgramClass> programClasses = builder.getProgramClasses().stream() - .collect(Collectors.toMap( - programClass -> programClass.type, - Function.identity())); - Collection<DexType> synthesized = new ArrayList<>(); - for (DexType dexType : inputMainDexList) { - DexProgramClass programClass = programClasses.get(dexType); - if (programClass != null) { - synthesized.addAll(DexAnnotation.readAnnotationSynthesizedClassMap( - programClass, builder.dexItemFactory)); - } - } - builder.addToMainDexList(synthesized); + private void updateMainDexListWithSynthesizedClassMap(AppView<?> appView, Builder<?> builder) { + MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses(); + if (mainDexClasses.isEmpty()) { + return; } + Map<DexType, DexProgramClass> programClasses = + builder.getProgramClasses().stream() + .collect(Collectors.toMap(programClass -> programClass.type, Function.identity())); + List<DexProgramClass> newMainDexClasses = new ArrayList<>(); + mainDexClasses.forEach( + mainDexClass -> { + DexProgramClass definition = programClasses.get(mainDexClass); + if (definition == null) { + return; + } + Iterable<DexType> syntheticTypes = + readAnnotationSynthesizedClassMap(definition, appView.dexItemFactory()); + for (DexType syntheticType : syntheticTypes) { + DexProgramClass syntheticClass = programClasses.get(syntheticType); + if (syntheticClass != null) { + newMainDexClasses.add(syntheticClass); + } + } + }); + mainDexClasses.addAll(newMainDexClasses); } private void clearSynthesizedClassMapping(Builder<?> builder) { @@ -558,8 +572,7 @@ .stream() .map(dexProgramClass -> dexProgramClass.type) .forEach(synthesized::add); - synthesized.addAll( - DexAnnotation.readAnnotationSynthesizedClassMap(original, builder.dexItemFactory)); + synthesized.addAll(readAnnotationSynthesizedClassMap(original, builder.dexItemFactory)); DexAnnotation updatedAnnotation = DexAnnotation.createAnnotationSynthesizedClassMap(synthesized, builder.dexItemFactory); @@ -589,52 +602,53 @@ private void convertMethod(ProgramMethod method) { DexEncodedMethod definition = method.getDefinition(); - if (definition.getCode() != null) { - boolean matchesMethodFilter = options.methodMatchesFilter(definition); - if (matchesMethodFilter) { - if (appView.options().enableNeverMergePrefixes) { - for (DexString neverMergePrefix : neverMergePrefixes) { - // Synthetic classes will always be merged. - if (appView.appInfo().getSyntheticItems().isSyntheticClass(method.getHolder())) { - continue; - } - if (method.getHolderType().descriptor.startsWith(neverMergePrefix)) { - seenNeverMergePrefix.getAndSet(true); - } else { - seenNotNeverMergePrefix.getAndSet(true); - } - // Don't mix. - if (seenNeverMergePrefix.get() && seenNotNeverMergePrefix.get()) { - StringBuilder message = new StringBuilder(); - message - .append("Merging dex file containing classes with prefix") - .append(neverMergePrefixes.size() > 1 ? "es " : " "); - for (int i = 0; i < neverMergePrefixes.size(); i++) { - message - .append("'") - .append(neverMergePrefixes.get(0).toString().substring(1).replace('/', '.')) - .append("'") - .append(i < neverMergePrefixes.size() - 1 ? ", " : ""); - } - message.append(" with classes with any other prefixes is not allowed."); - throw new CompilationError(message.toString()); - } - } + if (definition.getCode() == null) { + return; + } + if (!options.methodMatchesFilter(definition)) { + return; + } + checkPrefixMerging(method); + if (options.isGeneratingClassFiles() + || !(options.passthroughDexCode && definition.getCode().isDexCode())) { + // We do not process in call graph order, so anything could be a leaf. + rewriteCode( + method, simpleOptimizationFeedback, OneTimeMethodProcessor.create(method, appView), null); + } else { + assert definition.getCode().isDexCode(); + } + if (!options.isGeneratingClassFiles()) { + updateHighestSortingStrings(definition); + } + } + + private void checkPrefixMerging(ProgramMethod method) { + if (!appView.options().enableNeverMergePrefixes) { + return; + } + for (DexString neverMergePrefix : neverMergePrefixes) { + if (method.getHolderType().descriptor.startsWith(neverMergePrefix)) { + seenNeverMergePrefix.getAndSet(true); + } else { + seenNotNeverMergePrefix.getAndSet(true); + } + // Don't mix. + // TODO(b/168001352): Consider requiring that no 'never merge' prefix is ever seen as a + // passthrough object. + if (seenNeverMergePrefix.get() && seenNotNeverMergePrefix.get()) { + StringBuilder message = new StringBuilder(); + message + .append("Merging dex file containing classes with prefix") + .append(neverMergePrefixes.size() > 1 ? "es " : " "); + for (int i = 0; i < neverMergePrefixes.size(); i++) { + message + .append("'") + .append(neverMergePrefixes.get(0).toString().substring(1).replace('/', '.')) + .append("'") + .append(i < neverMergePrefixes.size() - 1 ? ", " : ""); } - if (options.isGeneratingClassFiles() - || !(options.passthroughDexCode && definition.getCode().isDexCode())) { - // We do not process in call graph order, so anything could be a leaf. - rewriteCode( - method, - simpleOptimizationFeedback, - OneTimeMethodProcessor.create(method, appView), - null); - } else { - assert definition.getCode().isDexCode(); - } - if (!options.isGeneratingClassFiles()) { - updateHighestSortingStrings(definition); - } + message.append(" with classes with any other prefixes is not allowed."); + throw new CompilationError(message.toString()); } } } @@ -716,6 +730,9 @@ assert graphLensForIR == appView.graphLens(); } + // The field access info collection is not maintained during IR processing. + appView.appInfo().withLiveness().getFieldAccessInfoCollection().destroyAccessContexts(); + // Assure that no more optimization feedback left after primary processing. assert feedback.noUpdatesLeft(); appView.setAllCodeProcessed(); @@ -789,7 +806,7 @@ synthesizeTwrCloseResourceUtilityClass(builder, executorService); synthesizeJava8UtilityClass(builder, executorService); synthesizeRetargetClass(builder, executorService); - handleSynthesizedClassMapping(builder); + handleSynthesizedClassMapping(appView, builder); synthesizeEnumUnboxingUtilityMethods(builder, executorService); printPhase("Lambda merging finalization"); @@ -800,10 +817,10 @@ generateDesugaredLibraryAPIWrappers(builder, executorService); if (serviceLoaderRewriter != null && serviceLoaderRewriter.getSynthesizedClass() != null) { - appView.appInfo().addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass()); + appView.appInfo().addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass(), true); processSynthesizedServiceLoaderMethods( serviceLoaderRewriter.getSynthesizedClass(), executorService); - builder.addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass(), true); + builder.addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass()); } // Update optimization info for all synthesized methods at once. @@ -823,7 +840,7 @@ }, executorService); DexProgramClass outlineClass = outliner.buildOutlinerClass(computeOutlineClassType()); - appView.appInfo().addSynthesizedClass(outlineClass); + appView.appInfo().addSynthesizedClass(outlineClass, true); optimizeSynthesizedClass(outlineClass, executorService); forEachSelectedOutliningMethod( methodsSelectedForOutlining, @@ -836,7 +853,7 @@ executorService); feedback.updateVisibleOptimizationInfo(); assert outliner.checkAllOutlineSitesFoundAgain(); - builder.addSynthesizedClass(outlineClass, true); + builder.addSynthesizedClass(outlineClass); clearDexMethodCompilationState(outlineClass); } timing.end(); @@ -1239,7 +1256,7 @@ assert appView.enableWholeProgramOptimizations(); timing.begin("Collect optimization info"); collectOptimizationInfo( - method, code, ClassInitializerDefaultsResult.empty(), feedback, methodProcessor, timing); + context, code, ClassInitializerDefaultsResult.empty(), feedback, methodProcessor, timing); timing.end(); return timing; } @@ -1601,7 +1618,7 @@ if (appView.enableWholeProgramOptimizations()) { timing.begin("Collect optimization info"); collectOptimizationInfo( - method, code, classInitializerDefaultsResult, feedback, methodProcessor, timing); + context, code, classInitializerDefaultsResult, feedback, methodProcessor, timing); timing.end(); } @@ -1636,7 +1653,7 @@ // Compute optimization info summary for the current method unless it is pinned // (in that case we should not be making any assumptions about the behavior of the method). public void collectOptimizationInfo( - DexEncodedMethod method, + ProgramMethod method, IRCode code, ClassInitializerDefaultsResult classInitializerDefaultsResult, OptimizationFeedback feedback, @@ -1658,7 +1675,8 @@ } // Arguments can be changed during the debug mode. - boolean isDebugMode = options.debug || method.getOptimizationInfo().isReachabilitySensitive(); + boolean isDebugMode = + options.debug || method.getDefinition().getOptimizationInfo().isReachabilitySensitive(); if (!isDebugMode && appView.callSiteOptimizationInfoPropagator() != null) { timing.begin("Collect call-site info"); appView.callSiteOptimizationInfoPropagator().collectCallSiteOptimizationInfo(code, timing); @@ -1670,8 +1688,8 @@ } InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos = null; - if (method.isInitializer()) { - if (method.isClassInitializer()) { + if (method.getDefinition().isInitializer()) { + if (method.getDefinition().isClassInitializer()) { StaticFieldValueAnalysis.run( appView, code, classInitializerDefaultsResult, feedback, timing); } else { @@ -1681,12 +1699,7 @@ } } methodOptimizationInfoCollector.collectMethodOptimizationInfo( - code.method(), - code, - feedback, - dynamicTypeOptimization, - instanceFieldInitializationInfos, - timing); + method, code, feedback, dynamicTypeOptimization, instanceFieldInitializationInfos, timing); } public void removeDeadCodeAndFinalizeIR( @@ -1744,7 +1757,7 @@ timing.end(); } - private void markProcessed(IRCode code, OptimizationFeedback feedback) { + public void markProcessed(IRCode code, OptimizationFeedback feedback) { // After all the optimizations have take place, we compute whether method should be inlined. ProgramMethod method = code.context(); ConstraintWithTarget state =
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java index 51905bf..576a376 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.conversion; -import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.ARGUMENT_TO_LAMBDA_METAFACTORY; import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY; import static com.android.tools.r8.ir.code.Invoke.Type.STATIC; import static com.android.tools.r8.ir.code.Invoke.Type.VIRTUAL; @@ -41,13 +40,7 @@ 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.DexMethodHandle.MethodHandleType; -import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.DexValue; -import com.android.tools.r8.graph.DexValue.DexValueMethodHandle; -import com.android.tools.r8.graph.DexValue.DexValueMethodType; -import com.android.tools.r8.graph.DexValue.DexValueType; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; import com.android.tools.r8.graph.ProgramMethod; @@ -55,7 +48,6 @@ import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo; import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection; import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo; -import com.android.tools.r8.graph.UseRegistry.MethodHandleUse; import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses; import com.android.tools.r8.ir.analysis.type.DestructivePhiTypeUpdater; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -101,7 +93,6 @@ import java.util.ListIterator; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; public class LensCodeRewriter { @@ -109,11 +100,12 @@ private final AppView<? extends AppInfoWithClassHierarchy> appView; private final EnumUnboxer enumUnboxer; - private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>(); + private final LensCodeRewriterUtils helper; LensCodeRewriter(AppView<? extends AppInfoWithClassHierarchy> appView, EnumUnboxer enumUnboxer) { this.appView = appView; this.enumUnboxer = enumUnboxer; + this.helper = new LensCodeRewriterUtils(appView); } private Value makeOutValue(Instruction insn, IRCode code) { @@ -152,7 +144,7 @@ { InvokeCustom invokeCustom = current.asInvokeCustom(); DexCallSite callSite = invokeCustom.getCallSite(); - DexCallSite newCallSite = rewriteCallSite(callSite, method); + DexCallSite newCallSite = helper.rewriteCallSite(callSite, method); if (newCallSite != callSite) { Value newOutValue = makeOutValue(invokeCustom, code); InvokeCustom newInvokeCustom = @@ -169,7 +161,7 @@ { DexMethodHandle handle = current.asConstMethodHandle().getValue(); DexMethodHandle newHandle = - rewriteDexMethodHandle(handle, method, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY); + helper.rewriteDexMethodHandle(handle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, method); if (newHandle != handle) { Value newOutValue = makeOutValue(current, code); iterator.replaceCurrentInstruction(new ConstMethodHandle(newOutValue, newHandle)); @@ -632,28 +624,6 @@ return TypeElement.getNull(); } - public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) { - DexItemFactory dexItemFactory = appView.dexItemFactory(); - DexProto newMethodProto = - dexItemFactory.applyClassMappingToProto( - callSite.methodProto, appView.graphLens()::lookupType, protoFixupCache); - DexMethodHandle newBootstrapMethod = - rewriteDexMethodHandle( - callSite.bootstrapMethod, context, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY); - boolean isLambdaMetaFactory = - dexItemFactory.isLambdaMetafactoryMethod(callSite.bootstrapMethod.asMethod()); - MethodHandleUse methodHandleUse = - isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY; - List<DexValue> newArgs = rewriteBootstrapArgs(callSite.bootstrapArgs, context, methodHandleUse); - if (!newMethodProto.equals(callSite.methodProto) - || newBootstrapMethod != callSite.bootstrapMethod - || !newArgs.equals(callSite.bootstrapArgs)) { - return dexItemFactory.createCallSite( - callSite.methodName, newMethodProto, newBootstrapMethod, newArgs); - } - return callSite; - } - // If the given invoke is on the form "invoke-direct A.<init>, v0, ..." and the definition of // value v0 is "new-instance v0, B", where B is a subtype of A (see the Art800 and B116282409 // tests), then fail with a compilation error if A has previously been merged into B. @@ -731,116 +701,6 @@ return !deadCatchHandlers.isEmpty(); } - private List<DexValue> rewriteBootstrapArgs( - List<DexValue> bootstrapArgs, ProgramMethod method, MethodHandleUse use) { - List<DexValue> newBootstrapArgs = null; - boolean changed = false; - for (int i = 0; i < bootstrapArgs.size(); i++) { - DexValue argument = bootstrapArgs.get(i); - DexValue newArgument = null; - switch (argument.getValueKind()) { - case METHOD_HANDLE: - newArgument = rewriteDexValueMethodHandle(argument.asDexValueMethodHandle(), method, use); - break; - case METHOD_TYPE: - newArgument = rewriteDexMethodType(argument.asDexValueMethodType()); - break; - case TYPE: - DexType oldType = argument.asDexValueType().value; - DexType newType = appView.graphLens().lookupType(oldType); - if (newType != oldType) { - newArgument = new DexValueType(newType); - } - break; - default: - // Intentionally empty. - } - if (newArgument != null) { - if (newBootstrapArgs == null) { - newBootstrapArgs = new ArrayList<>(bootstrapArgs.subList(0, i)); - } - newBootstrapArgs.add(newArgument); - changed = true; - } else if (newBootstrapArgs != null) { - newBootstrapArgs.add(argument); - } - } - return changed ? newBootstrapArgs : bootstrapArgs; - } - - private DexValueMethodHandle rewriteDexValueMethodHandle( - DexValueMethodHandle methodHandle, ProgramMethod context, MethodHandleUse use) { - DexMethodHandle oldHandle = methodHandle.value; - DexMethodHandle newHandle = rewriteDexMethodHandle(oldHandle, context, use); - return newHandle != oldHandle ? new DexValueMethodHandle(newHandle) : methodHandle; - } - - private DexMethodHandle rewriteDexMethodHandle( - DexMethodHandle methodHandle, ProgramMethod context, MethodHandleUse use) { - if (methodHandle.isMethodHandle()) { - DexMethod invokedMethod = methodHandle.asMethod(); - MethodHandleType oldType = methodHandle.type; - GraphLensLookupResult lensLookup = - appView - .graphLens() - .lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType()); - DexMethod rewrittenTarget = lensLookup.getMethod(); - DexMethod actualTarget; - MethodHandleType newType; - if (use == ARGUMENT_TO_LAMBDA_METAFACTORY) { - // Lambda metafactory arguments will be lambda desugared away and therefore cannot flow - // to a MethodHandle.invokeExact call. We can therefore member-rebind with no issues. - actualTarget = rewrittenTarget; - newType = lensLookup.getType().toMethodHandle(actualTarget); - } else { - assert use == NOT_ARGUMENT_TO_LAMBDA_METAFACTORY; - // MethodHandles that are not arguments to a lambda metafactory will not be desugared - // away. Therefore they could flow to a MethodHandle.invokeExact call which means that - // we cannot member rebind. We therefore keep the receiver and also pin the receiver - // with a keep rule (see Enqueuer.registerMethodHandle). - actualTarget = - appView - .dexItemFactory() - .createMethod(invokedMethod.holder, rewrittenTarget.proto, rewrittenTarget.name); - newType = oldType; - if (oldType.isInvokeDirect()) { - // For an invoke direct, the rewritten target must have the same holder as the original. - // If the method has changed from private to public we need to use virtual instead of - // direct. - assert rewrittenTarget.holder == actualTarget.holder; - newType = lensLookup.getType().toMethodHandle(actualTarget); - assert newType == MethodHandleType.INVOKE_DIRECT - || newType == MethodHandleType.INVOKE_INSTANCE; - } - } - if (newType != oldType || actualTarget != invokedMethod || rewrittenTarget != actualTarget) { - DexClass holder = appView.definitionFor(actualTarget.holder); - boolean isInterface = holder != null ? holder.isInterface() : methodHandle.isInterface; - return new DexMethodHandle( - newType, - actualTarget, - isInterface, - rewrittenTarget != actualTarget ? rewrittenTarget : null); - } - } else { - DexField field = methodHandle.asField(); - DexField actualField = appView.graphLens().lookupField(field); - if (actualField != field) { - return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface); - } - } - return methodHandle; - } - - private DexValueMethodType rewriteDexMethodType(DexValueMethodType type) { - DexProto oldProto = type.value; - DexProto newProto = - appView - .dexItemFactory() - .applyClassMappingToProto(oldProto, appView.graphLens()::lookupType, protoFixupCache); - return newProto != oldProto ? new DexValueMethodType(newProto) : type; - } - class InstructionReplacer { private final IRCode code;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java new file mode 100644 index 0000000..27b3064 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -0,0 +1,180 @@ +// 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.conversion; + +import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.ARGUMENT_TO_LAMBDA_METAFACTORY; +import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexCallSite; +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.DexItemFactory; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexMethodHandle; +import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType; +import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexValue; +import com.android.tools.r8.graph.DexValue.DexValueMethodHandle; +import com.android.tools.r8.graph.DexValue.DexValueMethodType; +import com.android.tools.r8.graph.DexValue.DexValueType; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.graph.UseRegistry.MethodHandleUse; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class LensCodeRewriterUtils { + + private final DexDefinitionSupplier definitions; + private final GraphLens graphLens; + + private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>(); + + public LensCodeRewriterUtils(AppView<?> appView) { + this(appView, appView.graphLens()); + } + + public LensCodeRewriterUtils(DexDefinitionSupplier definitions, GraphLens graphLens) { + this.definitions = definitions; + this.graphLens = graphLens; + } + + public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) { + DexItemFactory dexItemFactory = definitions.dexItemFactory(); + DexProto newMethodProto = rewriteProto(callSite.methodProto); + DexMethodHandle newBootstrapMethod = + rewriteDexMethodHandle( + callSite.bootstrapMethod, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context); + boolean isLambdaMetaFactory = + dexItemFactory.isLambdaMetafactoryMethod(callSite.bootstrapMethod.asMethod()); + MethodHandleUse methodHandleUse = + isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY; + List<DexValue> newArgs = + rewriteBootstrapArguments(callSite.bootstrapArgs, methodHandleUse, context); + if (!newMethodProto.equals(callSite.methodProto) + || newBootstrapMethod != callSite.bootstrapMethod + || !newArgs.equals(callSite.bootstrapArgs)) { + return dexItemFactory.createCallSite( + callSite.methodName, newMethodProto, newBootstrapMethod, newArgs); + } + return callSite; + } + + public DexMethodHandle rewriteDexMethodHandle( + DexMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) { + if (methodHandle.isMethodHandle()) { + DexMethod invokedMethod = methodHandle.asMethod(); + MethodHandleType oldType = methodHandle.type; + GraphLensLookupResult lensLookup = + graphLens.lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType()); + DexMethod rewrittenTarget = lensLookup.getMethod(); + DexMethod actualTarget; + MethodHandleType newType; + if (use == ARGUMENT_TO_LAMBDA_METAFACTORY) { + // Lambda metafactory arguments will be lambda desugared away and therefore cannot flow + // to a MethodHandle.invokeExact call. We can therefore member-rebind with no issues. + actualTarget = rewrittenTarget; + newType = lensLookup.getType().toMethodHandle(actualTarget); + } else { + assert use == NOT_ARGUMENT_TO_LAMBDA_METAFACTORY; + // MethodHandles that are not arguments to a lambda metafactory will not be desugared + // away. Therefore they could flow to a MethodHandle.invokeExact call which means that + // we cannot member rebind. We therefore keep the receiver and also pin the receiver + // with a keep rule (see Enqueuer.registerMethodHandle). + actualTarget = + definitions + .dexItemFactory() + .createMethod(invokedMethod.holder, rewrittenTarget.proto, rewrittenTarget.name); + newType = oldType; + if (oldType.isInvokeDirect()) { + // For an invoke direct, the rewritten target must have the same holder as the original. + // If the method has changed from private to public we need to use virtual instead of + // direct. + assert rewrittenTarget.holder == actualTarget.holder; + newType = lensLookup.getType().toMethodHandle(actualTarget); + assert newType == MethodHandleType.INVOKE_DIRECT + || newType == MethodHandleType.INVOKE_INSTANCE; + } + } + if (newType != oldType || actualTarget != invokedMethod || rewrittenTarget != actualTarget) { + DexClass holder = definitions.definitionFor(actualTarget.holder, context); + boolean isInterface = holder != null ? holder.isInterface() : methodHandle.isInterface; + return new DexMethodHandle( + newType, + actualTarget, + isInterface, + rewrittenTarget != actualTarget ? rewrittenTarget : null); + } + } else { + DexField field = methodHandle.asField(); + DexField actualField = graphLens.lookupField(field); + if (actualField != field) { + return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface); + } + } + return methodHandle; + } + + private List<DexValue> rewriteBootstrapArguments( + List<DexValue> bootstrapArgs, MethodHandleUse use, ProgramMethod context) { + List<DexValue> newBootstrapArgs = null; + boolean changed = false; + for (int i = 0; i < bootstrapArgs.size(); i++) { + DexValue argument = bootstrapArgs.get(i); + DexValue newArgument = rewriteBootstrapArgument(argument, use, context); + if (newArgument != argument) { + if (newBootstrapArgs == null) { + newBootstrapArgs = new ArrayList<>(bootstrapArgs.subList(0, i)); + } + newBootstrapArgs.add(newArgument); + changed = true; + } else if (newBootstrapArgs != null) { + newBootstrapArgs.add(newArgument); + } + } + return changed ? newBootstrapArgs : bootstrapArgs; + } + + private DexValueMethodType rewriteDexMethodType(DexValueMethodType type) { + DexProto oldProto = type.value; + DexProto newProto = rewriteProto(oldProto); + return newProto != oldProto ? new DexValueMethodType(newProto) : type; + } + + private DexValue rewriteBootstrapArgument( + DexValue value, MethodHandleUse use, ProgramMethod context) { + switch (value.getValueKind()) { + case METHOD_HANDLE: + return rewriteDexValueMethodHandle(value.asDexValueMethodHandle(), use, context); + case METHOD_TYPE: + return rewriteDexMethodType(value.asDexValueMethodType()); + case TYPE: + DexType oldType = value.asDexValueType().value; + DexType newType = graphLens.lookupType(oldType); + return newType != oldType ? new DexValueType(newType) : value; + default: + return value; + } + } + + public DexProto rewriteProto(DexProto proto) { + return definitions + .dexItemFactory() + .applyClassMappingToProto(proto, graphLens::lookupType, protoFixupCache); + } + + private DexValueMethodHandle rewriteDexValueMethodHandle( + DexValueMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) { + DexMethodHandle oldHandle = methodHandle.value; + DexMethodHandle newHandle = rewriteDexMethodHandle(oldHandle, use, context); + return newHandle != oldHandle ? new DexValueMethodHandle(newHandle) : methodHandle; + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java index e54ec6c..4379da1 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -35,6 +35,8 @@ void methodReturnsAbstractValue( DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue abstractValue); + void unsetAbstractReturnValue(DexEncodedMethod method); + void methodReturnsObjectWithUpperBoundType( DexEncodedMethod method, AppView<?> appView, TypeElement type);
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 347f495..5c08f1f 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
@@ -221,9 +221,8 @@ ParameterAnnotationsList.empty(), code, true); - boolean addToMainDexList = - referencingClasses.stream() - .anyMatch(clazz -> appView.appInfo().isInMainDexList(clazz.type)); + boolean addToMainDexClasses = + appView.appInfo().getMainDexClasses().containsAnyOf(referencingClasses); DexProgramClass utilityClass = synthesizeClassWithUniqueMethod( builder, @@ -231,7 +230,7 @@ method.holder, dexEncodedMethod, "java8 methods utility class", - addToMainDexList, + addToMainDexClasses, appView); // The following may add elements to methodsProviders. converter.optimizeSynthesizedClass(utilityClass, executorService); @@ -244,7 +243,7 @@ DexType type, DexEncodedMethod uniqueMethod, String origin, - boolean addToMainDexList, + boolean addToMainDexClasses, AppView<?> appView) { DexItemFactory factory = appView.dexItemFactory(); DexProgramClass newClass = @@ -271,8 +270,8 @@ : new DexEncodedMethod[] {uniqueMethod}, factory.getSkipNameValidationForTesting(), getChecksumSupplier(uniqueMethod, appView)); - appView.appInfo().addSynthesizedClass(newClass); - builder.addSynthesizedClass(newClass, addToMainDexList); + appView.appInfo().addSynthesizedClass(newClass, addToMainDexClasses); + builder.addSynthesizedClass(newClass); return newClass; }
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 23a6465..7936ffd 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
@@ -525,8 +525,8 @@ Collection<DexProgramClass> wrappers) throws ExecutionException { for (DexProgramClass wrapper : wrappers) { - builder.addSynthesizedClass(wrapper, false); - appView.appInfo().addSynthesizedClass(wrapper); + builder.addSynthesizedClass(wrapper); + appView.appInfo().addSynthesizedClass(wrapper, false); } irConverter.optimizeSynthesizedClasses(wrappers, executorService); }
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 6f46dc6..aa15050 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
@@ -41,6 +41,7 @@ import com.android.tools.r8.origin.Origin; import com.android.tools.r8.origin.SynthesizedOrigin; import com.android.tools.r8.position.MethodPosition; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.IterableUtils; @@ -532,17 +533,21 @@ private void generateEmulateInterfaceLibrary(Builder<?> builder) { // Emulated library interfaces should generate the Emulated Library EL dispatch class. Map<DexType, List<DexType>> emulatedInterfacesHierarchy = processEmulatedInterfaceHierarchy(); + AppInfo appInfo = appView.appInfo(); + MainDexClasses mainDexClasses = appInfo.getMainDexClasses(); for (DexType interfaceType : emulatedInterfaces.keySet()) { - DexClass theInterface = appView.definitionFor(interfaceType); + DexClass theInterface = appInfo.definitionFor(interfaceType); if (theInterface == null) { warnMissingEmulatedInterface(interfaceType); } else if (theInterface.isProgramClass()) { + DexProgramClass theProgramInterface = theInterface.asProgramClass(); DexProgramClass synthesizedClass = synthesizeEmulateInterfaceLibraryClass( - theInterface.asProgramClass(), emulatedInterfacesHierarchy); + theProgramInterface, emulatedInterfacesHierarchy); if (synthesizedClass != null) { - builder.addSynthesizedClass(synthesizedClass, isInMainDexList(interfaceType)); - appView.appInfo().addSynthesizedClass(synthesizedClass); + builder.addSynthesizedClass(synthesizedClass); + appInfo.addSynthesizedClass( + synthesizedClass, mainDexClasses.contains(theProgramInterface)); } } } @@ -797,10 +802,6 @@ return factory.createType(interfaceTypeDescriptor); } - private boolean isInMainDexList(DexType iface) { - return appView.appInfo().isInMainDexList(iface); - } - // Represent a static interface method as a method of companion class. final DexMethod staticAsMethodOfCompanionClass(DexMethod method) { // No changes for static methods. @@ -1000,13 +1001,18 @@ // make original default methods abstract, remove bridge methods, create dispatch // classes if needed. AppInfo appInfo = appView.appInfo(); - for (Entry<DexType, DexProgramClass> entry : processInterfaces(builder, flavour).entrySet()) { - // Don't need to optimize synthesized class since all of its methods - // are just moved from interfaces and don't need to be re-processed. - DexProgramClass synthesizedClass = entry.getValue(); - builder.addSynthesizedClass(synthesizedClass, isInMainDexList(entry.getKey())); - appInfo.addSynthesizedClass(synthesizedClass); - } + MainDexClasses mainDexClasses = appInfo.getMainDexClasses(); + processInterfaces(builder, flavour) + .forEach( + (interfaceClass, synthesizedClass) -> { + // Don't need to optimize synthesized class since all of its methods + // are just moved from interfaces and don't need to be re-processed. + builder.addSynthesizedClass(synthesizedClass); + boolean addToMainDexClasses = + interfaceClass.isProgramClass() + && mainDexClasses.contains(interfaceClass.asProgramClass()); + appInfo.addSynthesizedClass(synthesizedClass, addToMainDexClasses); + }); if (appView.options().isDesugaredLibraryCompilation()) { renameEmulatedInterfaces(); @@ -1030,7 +1036,7 @@ && clazz.isInterface() == mustBeInterface; } - private Map<DexType, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) { + private Map<DexClass, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) { InterfaceProcessorNestedGraphLens.Builder graphLensBuilder = InterfaceProcessorNestedGraphLens.builder(); InterfaceProcessor processor = new InterfaceProcessor(appView, this);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java index 6864127..a792f06 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -59,7 +59,7 @@ private final InterfaceMethodRewriter rewriter; // All created companion and dispatch classes indexed by interface type. - final Map<DexType, DexProgramClass> syntheticClasses = new IdentityHashMap<>(); + final Map<DexClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>(); InterfaceProcessor( AppView<?> appView, InterfaceMethodRewriter rewriter) { @@ -221,7 +221,7 @@ rewriter.factory.getSkipNameValidationForTesting(), getChecksumSupplier(iface), Collections.singletonList(iface)); - syntheticClasses.put(iface.type, companionClass); + syntheticClasses.put(iface, companionClass); } private ChecksumSupplier getChecksumSupplier(DexProgramClass iface) { @@ -307,7 +307,7 @@ rewriter.factory.getSkipNameValidationForTesting(), DexProgramClass::checksumFromType, callers); - syntheticClasses.put(iface.type, dispatchClass); + syntheticClasses.put(iface, dispatchClass); return dispatchClass; }
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 8deb4fc..104fc97 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
@@ -167,7 +167,7 @@ synthesizeVirtualMethods(mainMethod), appView.dexItemFactory().getSkipNameValidationForTesting(), LambdaClass::computeChecksumForSynthesizedClass); - appView.appInfo().addSynthesizedClass(clazz); + appView.appInfo().addSynthesizedClass(clazz, false); // The method addSynthesizedFrom() may be called concurrently. To avoid a Concurrent- // ModificationException we must use synchronization.
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 c4709c7..dd7889d 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
@@ -157,8 +157,8 @@ knownLambdaClasses.values(), converter, executorService); for (LambdaClass lambdaClass : knownLambdaClasses.values()) { DexProgramClass synthesizedClass = lambdaClass.getOrCreateLambdaClass(); - appView.appInfo().addSynthesizedClass(synthesizedClass); - builder.addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get()); + appView.appInfo().addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get()); + builder.addSynthesizedClass(synthesizedClass); } optimizeSynthesizedClasses(converter, executorService); } @@ -190,10 +190,6 @@ LambdaDescriptor.infer(callSite, appView.appInfoForDesugaring(), context)); } - private boolean isInMainDexList(DexType 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( @@ -224,7 +220,7 @@ } } lambdaClass.addSynthesizedFrom(accessedFrom.getHolder()); - if (isInMainDexList(accessedFrom.getHolderType())) { + if (appView.appInfo().getMainDexClasses().contains(accessedFrom.getHolder())) { lambdaClass.addToMainDexList.set(true); } return lambdaClass;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java index 67571b3..8370326 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -196,15 +196,11 @@ void synthesizeNestConstructor(DexApplication.Builder<?> builder) { if (nestConstructorUsed) { - appView.appInfo().addSynthesizedClass(nestConstructor); - builder.addSynthesizedClass(nestConstructor, true); + appView.appInfo().addSynthesizedClass(nestConstructor, true); + builder.addSynthesizedClass(nestConstructor); } } - public static boolean isNestConstructor(DexType type) { - return type.getName().equals(NEST_CONSTRUCTOR_NAME); - } - private DexString computeMethodBridgeName(DexEncodedMethod method) { String methodName = method.method.name.toString(); String fullName;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java index 4043023..613fac6 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -28,6 +28,7 @@ import com.android.tools.r8.ir.conversion.IRConverter; import com.android.tools.r8.ir.desugar.backports.BackportedMethods; import com.android.tools.r8.origin.SynthesizedOrigin; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.Sets; import java.util.Collections; @@ -161,10 +162,10 @@ // Process created class and method. AppInfo appInfo = appView.appInfo(); - boolean addToMainDexList = - referencingClasses.stream().anyMatch(clazz -> appInfo.isInMainDexList(clazz.type)); - appInfo.addSynthesizedClass(utilityClass); + MainDexClasses mainDexClasses = appInfo.getMainDexClasses(); + boolean addToMainDexList = mainDexClasses.containsAnyOf(referencingClasses); + appInfo.addSynthesizedClass(utilityClass, addToMainDexList); converter.optimizeSynthesizedClass(utilityClass, executorService); - builder.addSynthesizedClass(utilityClass, addToMainDexList); + builder.addSynthesizedClass(utilityClass); } }
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 fc01ffe..611a249 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
@@ -61,7 +61,7 @@ import com.android.tools.r8.ir.optimize.lambda.LambdaMerger; import com.android.tools.r8.kotlin.Kotlin; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.shaking.MainDexClasses; +import com.android.tools.r8.shaking.MainDexTracingResult; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.IteratorUtils; import com.android.tools.r8.utils.ListUtils; @@ -88,7 +88,7 @@ private final Set<DexMethod> blacklist; private final LambdaMerger lambdaMerger; private final LensCodeRewriter lensCodeRewriter; - final MainDexClasses mainDexClasses; + final MainDexTracingResult mainDexClasses; // State for inlining methods which are known to be called twice. private boolean applyDoubleInlining = false; @@ -101,7 +101,7 @@ public Inliner( AppView<AppInfoWithLiveness> appView, - MainDexClasses mainDexClasses, + MainDexTracingResult mainDexClasses, LambdaMerger lambdaMerger, LensCodeRewriter lensCodeRewriter) { Kotlin.Intrinsics intrinsics = appView.dexItemFactory().kotlin.intrinsics;
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 3d7d397..54b7f8d 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
@@ -108,7 +108,7 @@ private final Map<DexType, ProgramMethodSet> enumsUnboxingCandidates; private final Map<DexType, Set<DexField>> requiredEnumInstanceFieldData = new ConcurrentHashMap<>(); - private final Set<DexType> enumsToUnboxWithPackageRequirement = Sets.newIdentityHashSet(); + private final Set<DexProgramClass> enumsToUnboxWithPackageRequirement = Sets.newIdentityHashSet(); private EnumUnboxingRewriter enumUnboxerRewriter; @@ -440,17 +440,17 @@ } Map<DexType, DexType> newMethodLocationMap = new IdentityHashMap<>(); Map<String, DexProgramClass> packageToClassMap = new HashMap<>(); - for (DexType toUnbox : enumsToUnboxWithPackageRequirement) { - String packageDescriptor = toUnbox.getPackageDescriptor(); + for (DexProgramClass toUnbox : enumsToUnboxWithPackageRequirement) { + String packageDescriptor = toUnbox.getType().getPackageDescriptor(); DexProgramClass syntheticClass = packageToClassMap.get(packageDescriptor); if (syntheticClass == null) { syntheticClass = synthesizeUtilityClassInPackage(packageDescriptor, appBuilder); packageToClassMap.put(packageDescriptor, syntheticClass); } - if (appView.appInfo().isInMainDexList(toUnbox)) { - appBuilder.addToMainDexList(syntheticClass.type); + if (appView.appInfo().getMainDexClasses().contains(toUnbox)) { + appView.appInfo().getMainDexClasses().add(syntheticClass); } - newMethodLocationMap.put(toUnbox, syntheticClass.type); + newMethodLocationMap.put(toUnbox.getType(), syntheticClass.getType()); } enumsToUnboxWithPackageRequirement.clear(); return newMethodLocationMap; @@ -488,8 +488,8 @@ DexEncodedMethod.EMPTY_ARRAY, factory.getSkipNameValidationForTesting(), DexProgramClass::checksumFromType); - appBuilder.addSynthesizedClass(syntheticClass, false); - appView.appInfo().addSynthesizedClass(syntheticClass); + appBuilder.addSynthesizedClass(syntheticClass); + appView.appInfo().addSynthesizedClass(syntheticClass, false); return syntheticClass; } @@ -559,7 +559,7 @@ if (classConstraint == Constraint.NEVER) { markEnumAsUnboxable(Reason.ACCESSIBILITY, enumClass); } else if (classConstraint == Constraint.PACKAGE) { - enumsToUnboxWithPackageRequirement.add(toUnbox); + enumsToUnboxWithPackageRequirement.add(enumClass); } } } @@ -877,6 +877,10 @@ if (singleTarget == factory.javaLangSystemMethods.identityHashCode) { return Reason.ELIGIBLE; } + if (singleTarget == factory.stringMembers.valueOf) { + requiredEnumInstanceFieldData(enumClass.type, factory.enumMembers.nameField); + return Reason.ELIGIBLE; + } if (singleTarget == factory.objectMembers.getClass && (!invokeMethod.hasOutValue() || !invokeMethod.outValue().hasAnyUsers())) { // This is a hidden null check. @@ -1238,9 +1242,7 @@ }); clazz.getMethodCollection().removeMethods(methodsToRemove); } else { - clazz - .getMethodCollection() - .replaceMethods(encodedMethod -> fixupEncodedMethod(encodedMethod)); + clazz.getMethodCollection().replaceMethods(this::fixupEncodedMethod); fixupFields(clazz.staticFields(), clazz::setStaticField); fixupFields(clazz.instanceFields(), clazz::setInstanceField); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java index ca106ab..6c73aef 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -29,6 +29,7 @@ import com.android.tools.r8.ir.analysis.type.ArrayTypeElement; 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.code.ArrayAccess; import com.android.tools.r8.ir.code.ConstNumber; import com.android.tools.r8.ir.code.IRCode; @@ -205,15 +206,26 @@ continue; } } else if (invokedMethod == factory.javaLangSystemMethods.identityHashCode) { - assert invokeStatic.inValues().size() == 1; + assert invokeStatic.arguments().size() == 1; Value argument = invokeStatic.getArgument(0); DexType enumType = getEnumTypeOrNull(argument, convertedEnums); if (enumType != null) { invokeStatic.outValue().replaceUsers(argument); iterator.removeOrReplaceByDebugLocalRead(); } + } else if (invokedMethod == factory.stringMembers.valueOf) { + assert invokeStatic.arguments().size() == 1; + Value argument = invokeStatic.getArgument(0); + DexType enumType = getEnumTypeOrNull(argument, convertedEnums); + if (enumType != null) { + DexMethod stringValueOfMethod = computeStringValueOfUtilityMethod(enumType); + iterator.replaceCurrentInstruction( + new InvokeStatic( + stringValueOfMethod, invokeStatic.outValue(), invokeStatic.arguments())); + continue; + } } else if (invokedMethod == factory.objectsMethods.requireNonNull) { - assert invokeStatic.inValues().size() == 1; + assert invokeStatic.arguments().size() == 1; Value argument = invokeStatic.getArgument(0); DexType enumType = getEnumTypeOrNull(argument, convertedEnums); if (enumType != null) { @@ -221,7 +233,7 @@ iterator, invokeStatic, zeroCheckMethod, m -> synthesizeZeroCheckMethod()); } } else if (invokedMethod == factory.objectsMethods.requireNonNullWithMessage) { - assert invokeStatic.inValues().size() == 2; + assert invokeStatic.arguments().size() == 2; Value argument = invokeStatic.getArgument(0); DexType enumType = getEnumTypeOrNull(argument, convertedEnums); if (enumType != null) { @@ -407,7 +419,24 @@ factory.createProto(field.type, factory.intType), methodName); utilityMethods.computeIfAbsent( - fieldMethod, m -> synthesizeInstanceFieldMethod(m, enumType, field)); + fieldMethod, m -> synthesizeInstanceFieldMethod(m, enumType, field, null)); + return fieldMethod; + } + + private DexMethod computeStringValueOfUtilityMethod(DexType enumType) { + // TODO(b/167994636): remove duplication between instance field name read and this method. + assert enumsToUnbox.containsEnum(enumType); + String methodName = "string$valueOf$" + compatibleName(enumType); + DexMethod fieldMethod = + factory.createMethod( + factory.enumUnboxingUtilityType, + factory.createProto(factory.stringType, factory.intType), + methodName); + AbstractValue nullString = + appView.abstractValueFactory().createSingleStringValue(factory.createString("null")); + utilityMethods.computeIfAbsent( + fieldMethod, + m -> synthesizeInstanceFieldMethod(m, enumType, factory.enumMembers.nameField, nullString)); return fieldMethod; } @@ -458,9 +487,6 @@ utilityClass.appendStaticFields(fields); utilityClass.addDirectMethods(requiredMethods); assert requiredMethods.stream().allMatch(DexEncodedMethod::isPublic); - if (utilityClassInMainDexList()) { - builder.addToMainDexList(Collections.singletonList(utilityClass.type)); - } // TODO(b/147860220): Use processMethodsConcurrently on requiredMethods instead. converter.optimizeSynthesizedClass(utilityClass, executorService); } @@ -489,7 +515,7 @@ } private DexEncodedMethod synthesizeInstanceFieldMethod( - DexMethod method, DexType enumType, DexField field) { + DexMethod method, DexType enumType, DexField field, AbstractValue nullValue) { assert method.proto.returnType == field.type; assert unboxedEnumsInstanceFieldData.getInstanceFieldData(enumType, field).isMapping(); CfCode cfCode = @@ -500,7 +526,8 @@ enumsToUnbox.getEnumValueInfoMap(enumType), unboxedEnumsInstanceFieldData .getInstanceFieldData(enumType, field) - .asEnumFieldMappingData()) + .asEnumFieldMappingData(), + nullValue) .generateCfCode(); return synthesizeUtilityMethod(cfCode, method, false); } @@ -523,16 +550,6 @@ return synthesizeUtilityMethod(cfCode, method, false); } - // TODO(b/150178516): Add a test for this case. - private boolean utilityClassInMainDexList() { - for (DexType toUnbox : enumsToUnbox.enumSet()) { - if (appView.appInfo().isInMainDexList(toUnbox)) { - return true; - } - } - return false; - } - private DexEncodedMethod synthesizeZeroCheckMethod() { CfCode cfCode = EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheck(appView.options(), zeroCheckMethod);
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 b189a57..9125b1c 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
@@ -82,6 +82,7 @@ import com.android.tools.r8.ir.code.NewInstance; import com.android.tools.r8.ir.code.Return; import com.android.tools.r8.ir.code.Value; +import com.android.tools.r8.ir.conversion.IRConverter; import com.android.tools.r8.ir.optimize.DynamicTypeOptimization; import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo; import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerReceiverAnalysis; @@ -92,6 +93,7 @@ import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo; import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo; import com.android.tools.r8.ir.optimize.info.initializer.NonTrivialInstanceInitializerInfo; +import com.android.tools.r8.ir.optimize.typechecks.CheckCastAndInstanceOfMethodSpecialization; import com.android.tools.r8.kotlin.Kotlin; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.InternalOptions; @@ -112,37 +114,46 @@ import java.util.function.Predicate; public class MethodOptimizationInfoCollector { - private final AppView<AppInfoWithLiveness> appView; - private final InternalOptions options; - private final DexItemFactory dexItemFactory; - public MethodOptimizationInfoCollector(AppView<AppInfoWithLiveness> appView) { + private final AppView<AppInfoWithLiveness> appView; + private final CheckCastAndInstanceOfMethodSpecialization + checkCastAndInstanceOfMethodSpecialization; + private final DexItemFactory dexItemFactory; + private final InternalOptions options; + + public MethodOptimizationInfoCollector( + AppView<AppInfoWithLiveness> appView, IRConverter converter) { this.appView = appView; - this.options = appView.options(); + this.checkCastAndInstanceOfMethodSpecialization = + appView.options().isRelease() + ? new CheckCastAndInstanceOfMethodSpecialization(appView, converter) + : null; this.dexItemFactory = appView.dexItemFactory(); + this.options = appView.options(); } public void collectMethodOptimizationInfo( - DexEncodedMethod method, + ProgramMethod method, IRCode code, OptimizationFeedback feedback, DynamicTypeOptimization dynamicTypeOptimization, InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos, Timing timing) { - identifyBridgeInfo(method, code, feedback, timing); + DexEncodedMethod definition = method.getDefinition(); + identifyBridgeInfo(definition, code, feedback, timing); identifyClassInlinerEligibility(code, feedback, timing); - identifyParameterUsages(method, code, feedback, timing); - identifyReturnsArgument(code, feedback, timing); + identifyParameterUsages(definition, code, feedback, timing); + analyzeReturns(code, feedback, timing); if (options.enableInlining) { - identifyInvokeSemanticsForInlining(method, code, feedback, timing); + identifyInvokeSemanticsForInlining(definition, code, feedback, timing); } - computeDynamicReturnType(dynamicTypeOptimization, feedback, method, code, timing); - computeInitializedClassesOnNormalExit(feedback, method, code, timing); + computeDynamicReturnType(dynamicTypeOptimization, feedback, definition, code, timing); + computeInitializedClassesOnNormalExit(feedback, definition, code, timing); computeInstanceInitializerInfo( - method, code, feedback, instanceFieldInitializationInfos, timing); - computeMayHaveSideEffects(feedback, method, code, timing); - computeReturnValueOnlyDependsOnArguments(feedback, method, code, timing); - computeNonNullParamOrThrow(feedback, method, code, timing); + definition, code, feedback, instanceFieldInitializationInfos, timing); + computeMayHaveSideEffects(feedback, definition, code, timing); + computeReturnValueOnlyDependsOnArguments(feedback, definition, code, timing); + computeNonNullParamOrThrow(feedback, definition, code, timing); computeNonNullParamOnNormalExits(feedback, code, timing); } @@ -345,13 +356,13 @@ return builder.build(); } - private void identifyReturnsArgument(IRCode code, OptimizationFeedback feedback, Timing timing) { + private void analyzeReturns(IRCode code, OptimizationFeedback feedback, Timing timing) { timing.begin("Identify returns argument"); - identifyReturnsArgument(code, feedback); + analyzeReturns(code, feedback); timing.end(); } - private void identifyReturnsArgument(IRCode code, OptimizationFeedback feedback) { + private void analyzeReturns(IRCode code, OptimizationFeedback feedback) { ProgramMethod context = code.context(); DexEncodedMethod method = context.getDefinition(); List<BasicBlock> normalExits = code.computeNormalExitBlocks(); @@ -381,6 +392,10 @@ AbstractValue abstractReturnValue = definition.getAbstractValue(appView, context); if (abstractReturnValue.isNonTrivial()) { feedback.methodReturnsAbstractValue(method, appView, abstractReturnValue); + if (checkCastAndInstanceOfMethodSpecialization != null) { + checkCastAndInstanceOfMethodSpecialization.addCandidateForOptimization( + context, abstractReturnValue); + } } } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java index d9db007..07b7ce1 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -189,6 +189,11 @@ } @Override + public synchronized void unsetAbstractReturnValue(DexEncodedMethod method) { + getMethodOptimizationInfoForUpdating(method).unsetAbstractReturnValue(); + } + + @Override public synchronized void methodReturnsObjectWithUpperBoundType( DexEncodedMethod method, AppView<?> appView, TypeElement type) { getMethodOptimizationInfoForUpdating(method).markReturnsObjectWithUpperBoundType(appView, type);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java index 49ffaf9..6a28331 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -76,6 +76,9 @@ DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) {} @Override + public void unsetAbstractReturnValue(DexEncodedMethod method) {} + + @Override public void methodReturnsObjectWithUpperBoundType( DexEncodedMethod method, AppView<?> appView, TypeElement type) {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java index 62edebf..9a3bb51 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -98,7 +98,12 @@ @Override public void methodReturnsAbstractValue( DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) { - // Ignored. + method.getMutableOptimizationInfo().markReturnsAbstractValue(value); + } + + @Override + public void unsetAbstractReturnValue(DexEncodedMethod method) { + method.getMutableOptimizationInfo().unsetAbstractReturnValue(); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java index 610bad0..6d9fc9f 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -11,6 +11,7 @@ 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; +import com.android.tools.r8.ir.analysis.value.UnknownValue; import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo; import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage; import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo; @@ -406,6 +407,10 @@ abstractReturnValue = value; } + void unsetAbstractReturnValue() { + abstractReturnValue = UnknownValue.getInstance(); + } + void markReturnsObjectWithUpperBoundType(AppView<?> appView, TypeElement type) { assert type != null; // We may get more precise type information if the method is reprocessed (e.g., due to
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java index b80283b..0f6a8ed 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
@@ -16,6 +16,7 @@ import com.android.tools.r8.ir.optimize.info.OptimizationFeedback; import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy; import com.android.tools.r8.kotlin.Kotlin; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.utils.ThrowingConsumer; import com.google.common.collect.Lists; import com.google.common.io.BaseEncoding; @@ -58,6 +59,10 @@ this.id = id; this.clazz = clazz; } + + public DexProgramClass getLambdaClass() { + return clazz; + } } public LambdaGroup(LambdaGroupId id) { @@ -93,8 +98,9 @@ final boolean shouldAddToMainDex(AppView<?> appView) { // We add the group class to main index if any of the // lambda classes it replaces is added to main index. - for (DexType type : lambdas.keySet()) { - if (appView.appInfo().isInMainDexList(type)) { + MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses(); + for (LambdaInfo info : lambdas.values()) { + if (mainDexClasses.contains(info.getLambdaClass())) { return true; } }
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 a716bd4..a7b1576 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
@@ -367,8 +367,10 @@ // Add synthesized lambda group classes to the builder. for (Entry<LambdaGroup, DexProgramClass> entry : lambdaGroupsClasses.entrySet()) { DexProgramClass synthesizedClass = entry.getValue(); - appView.appInfo().addSynthesizedClass(synthesizedClass); - builder.addSynthesizedClass(synthesizedClass, entry.getKey().shouldAddToMainDex(appView)); + appView + .appInfo() + .addSynthesizedClass(synthesizedClass, entry.getKey().shouldAddToMainDex(appView)); + builder.addSynthesizedClass(synthesizedClass); // Eventually, we need to process synthesized methods in the lambda group. // Otherwise, abstract SynthesizedCode will be flown to Enqueuer. // But that process should not see the holder. Otherwise, lambda calls in the main dispatch
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java index 6ad81c8..06a3b1a 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -402,7 +402,7 @@ OptimizationFeedback feedback) { return (code, methodProcessor) -> converter.collectOptimizationInfo( - code.method(), + code.context(), code, ClassInitializerDefaultsResult.empty(), feedback,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java new file mode 100644 index 0000000..a8f3018 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -0,0 +1,164 @@ +// 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.typechecks; + +import static com.android.tools.r8.graph.AccessControl.isClassAccessible; +import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult; +import com.android.tools.r8.ir.analysis.value.AbstractValue; +import com.android.tools.r8.ir.code.IRCode; +import com.android.tools.r8.ir.conversion.IRConverter; +import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo; +import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; +import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.Action; +import com.android.tools.r8.utils.collections.ProgramMethodSet; + +/** + * An optimization that merges a method override (B.m()) into the method it overrides (A.m()). + * + * <p>If the method and its override effectively implement an 'instanceof B' instruction, i.e., + * A.m() returns false and B.m() returns true, then B.m() is removed and the body of A.m() is + * updated to {@code return this instanceof B}. + * + * <p>If the method and its override implement 'not instanceof B', then B.m() is removed and the + * body of A.m() is updated to {@code return !(this instance B)}. + * + * <p>TODO(b/151596599): Also handle methods that implement casts. + */ +public class CheckCastAndInstanceOfMethodSpecialization implements Action { + + private static final OptimizationFeedbackSimple feedback = + OptimizationFeedbackSimple.getInstance(); + + private final AppView<AppInfoWithLiveness> appView; + private final IRConverter converter; + + private final ProgramMethodSet candidatesForInstanceOfOptimization = + ProgramMethodSet.createSorted(); + + public CheckCastAndInstanceOfMethodSpecialization( + AppView<AppInfoWithLiveness> appView, IRConverter converter) { + assert !appView.options().debug; + this.appView = appView; + this.converter = converter; + } + + public void addCandidateForOptimization(ProgramMethod method, AbstractValue abstractReturnValue) { + if (!converter.isInWave()) { + return; + } + if (isCandidateForInstanceOfOptimization(method, abstractReturnValue)) { + synchronized (this) { + if (candidatesForInstanceOfOptimization.isEmpty()) { + converter.addWaveDoneAction(this); + } + candidatesForInstanceOfOptimization.add(method); + } + } + } + + private boolean isCandidateForInstanceOfOptimization( + ProgramMethod method, AbstractValue abstractReturnValue) { + return method.getReference().getReturnType().isBooleanType() + && abstractReturnValue.isSingleBoolean(); + } + + @Override + public void execute() { + assert !candidatesForInstanceOfOptimization.isEmpty(); + ProgramMethodSet processed = ProgramMethodSet.create(); + for (ProgramMethod method : candidatesForInstanceOfOptimization) { + if (!processed.contains(method)) { + processCandidateForInstanceOfOptimization(method); + } + } + } + + private void processCandidateForInstanceOfOptimization(ProgramMethod method) { + DexEncodedMethod definition = method.getDefinition(); + if (!definition.isNonPrivateVirtualMethod()) { + return; + } + + MethodOptimizationInfo optimizationInfo = method.getDefinition().getOptimizationInfo(); + if (optimizationInfo.mayHaveSideEffects()) { + return; + } + + AbstractValue abstractReturnValue = optimizationInfo.getAbstractReturnValue(); + if (!abstractReturnValue.isSingleBoolean()) { + return; + } + + ProgramMethod parentMethod = resolveOnSuperClass(method); + if (parentMethod == null || !parentMethod.getDefinition().isNonPrivateVirtualMethod()) { + return; + } + + MethodOptimizationInfo parentOptimizationInfo = + parentMethod.getDefinition().getOptimizationInfo(); + if (parentOptimizationInfo.mayHaveSideEffects()) { + return; + } + + AbstractValue abstractParentReturnValue = parentOptimizationInfo.getAbstractReturnValue(); + if (!abstractParentReturnValue.isSingleBoolean()) { + return; + } + + // Verify that the methods are not pinned. They shouldn't be, since we've computed an abstract + // return value for both. + assert !appView.appInfo().isPinned(method.getReference()); + assert !appView.appInfo().isPinned(parentMethod.getReference()); + + if (appView + .appInfo() + .getObjectAllocationInfoCollection() + .hasInstantiatedStrictSubtype(method.getHolder())) { + return; + } + + DexEncodedMethod parentMethodDefinition = parentMethod.getDefinition(); + if (abstractParentReturnValue == abstractReturnValue) { + // The parent method is already guaranteed to return the same value. + } else if (isClassAccessible(method.getHolder(), parentMethod, appView).isTrue()) { + parentMethodDefinition.setCode( + parentMethodDefinition.buildInstanceOfCode( + method.getHolderType(), abstractParentReturnValue.isTrue(), appView.options()), + appView); + // Rebuild inlining constraints. + IRCode code = + parentMethodDefinition.getCode().buildIR(parentMethod, appView, parentMethod.getOrigin()); + converter.markProcessed(code, feedback); + // Fixup method optimization info (the method no longer returns a constant). + feedback.unsetAbstractReturnValue(parentMethod.getDefinition()); + } else { + return; + } + + method.getHolder().removeMethod(method.getReference()); + } + + private ProgramMethod resolveOnSuperClass(ProgramMethod method) { + DexProgramClass superClass = + asProgramClassOrNull(appView.definitionFor(method.getHolder().superType)); + if (superClass == null) { + return null; + } + + SingleResolutionResult resolutionResult = + appView.appInfo().resolveMethodOn(superClass, method.getReference()).asSingleResolution(); + if (resolutionResult == null) { + return null; + } + return resolutionResult.getResolvedProgramMethod(); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java index cb1823a..5036205 100644 --- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java +++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -8,6 +8,8 @@ import com.android.tools.r8.cf.code.CfConstNull; import com.android.tools.r8.cf.code.CfConstString; import com.android.tools.r8.cf.code.CfFieldInstruction; +import com.android.tools.r8.cf.code.CfFrame; +import com.android.tools.r8.cf.code.CfFrame.FrameType; import com.android.tools.r8.cf.code.CfIf; import com.android.tools.r8.cf.code.CfInstanceOf; import com.android.tools.r8.cf.code.CfInstruction; @@ -30,6 +32,8 @@ import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter; +import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Opcodes; @@ -234,6 +238,11 @@ DexItemFactory factory = appView.dexItemFactory(); List<CfInstruction> instructions = new ArrayList<>(); + ImmutableInt2ReferenceSortedMap<FrameType> locals = + ImmutableInt2ReferenceSortedMap.<FrameType>builder() + .put(0, FrameType.initialized(argType)) + .build(); + // if (arg == null) { return null }; CfLabel nullDest = new CfLabel(); instructions.add(new CfLoad(ValueType.fromDexType(argType), 0)); @@ -241,6 +250,7 @@ instructions.add(new CfConstNull()); instructions.add(new CfReturn(ValueType.OBJECT)); instructions.add(nullDest); + instructions.add(new CfFrame(locals, ImmutableList.of())); // if (arg instanceOf ReverseWrapper) { return ((ReverseWrapper) arg).wrapperField}; assert reverseWrapperField != null; @@ -254,6 +264,7 @@ new CfFieldInstruction(Opcodes.GETFIELD, reverseWrapperField, reverseWrapperField)); instructions.add(new CfReturn(ValueType.fromDexType(reverseWrapperField.type))); instructions.add(unwrapDest); + instructions.add(new CfFrame(locals, ImmutableList.of())); // return new Wrapper(wrappedValue); instructions.add(new CfNew(wrapperField.holder));
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java index 3cb4210..e0579ed 100644 --- a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java +++ b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
@@ -5,6 +5,8 @@ package com.android.tools.r8.ir.synthetic; import com.android.tools.r8.cf.code.CfCheckCast; +import com.android.tools.r8.cf.code.CfFrame; +import com.android.tools.r8.cf.code.CfFrame.FrameType; import com.android.tools.r8.cf.code.CfIf; import com.android.tools.r8.cf.code.CfInstanceOf; import com.android.tools.r8.cf.code.CfInstruction; @@ -20,6 +22,8 @@ import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.utils.Pair; +import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Opcodes; @@ -53,6 +57,15 @@ } int nextLabel = 0; + ImmutableInt2ReferenceSortedMap.Builder<FrameType> localsBuilder = + ImmutableInt2ReferenceSortedMap.builder(); + localsBuilder.put(0, FrameType.initialized(interfaceType)); + int index = 1; + for (DexType param : libraryMethod.proto.parameters.values) { + localsBuilder.put(index++, FrameType.initialized(param)); + } + ImmutableInt2ReferenceSortedMap<FrameType> locals = localsBuilder.build(); + instructions.add(new CfLoad(ValueType.fromDexType(interfaceType), 0)); instructions.add(new CfInstanceOf(libraryMethod.holder)); instructions.add(new CfIf(If.Type.EQ, ValueType.INT, labels[nextLabel])); @@ -68,6 +81,7 @@ for (Pair<DexType, DexMethod> dispatch : extraDispatchCases) { // Type check basic block. instructions.add(labels[nextLabel++]); + instructions.add(new CfFrame(locals, ImmutableList.of())); instructions.add(new CfLoad(ValueType.fromDexType(interfaceType), 0)); instructions.add(new CfInstanceOf(dispatch.getFirst())); instructions.add(new CfIf(If.Type.EQ, ValueType.INT, labels[nextLabel])); @@ -82,6 +96,7 @@ // Branch with companion call. instructions.add(labels[nextLabel]); + instructions.add(new CfFrame(locals, ImmutableList.of())); instructions.add(new CfLoad(ValueType.fromDexType(interfaceType), 0)); loadExtraParameters(instructions); instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, companionMethod, false));
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java index 8b35793..52cdb30 100644 --- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java +++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -8,6 +8,8 @@ import com.android.tools.r8.cf.code.CfConstNumber; import com.android.tools.r8.cf.code.CfConstString; import com.android.tools.r8.cf.code.CfFieldInstruction; +import com.android.tools.r8.cf.code.CfFrame; +import com.android.tools.r8.cf.code.CfFrame.FrameType; import com.android.tools.r8.cf.code.CfIf; import com.android.tools.r8.cf.code.CfIfCmp; import com.android.tools.r8.cf.code.CfInstruction; @@ -31,6 +33,8 @@ import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData; +import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Opcodes; @@ -62,21 +66,26 @@ private final DexType returnType; private final EnumValueInfoMap enumValueInfoMap; private final EnumInstanceFieldMappingData fieldDataMap; + private final AbstractValue nullValue; public EnumUnboxingInstanceFieldCfCodeProvider( AppView<?> appView, DexType holder, DexType returnType, EnumValueInfoMap enumValueInfoMap, - EnumInstanceFieldMappingData fieldDataMap) { + EnumInstanceFieldMappingData fieldDataMap, + AbstractValue nullValue) { super(appView, holder); this.returnType = returnType; this.enumValueInfoMap = enumValueInfoMap; this.fieldDataMap = fieldDataMap; + this.nullValue = nullValue; } @Override public CfCode generateCfCode() { + // TODO(b/167942775): Should use a table-switch for large enums (maybe same threshold in the + // rewriter of switchmaps). // Generated static method, for class com.x.MyEnum {A(10),B(20);} would look like: // String UtilityClass#com.x.MyEnum_toString(int i) { // if (i == 1) { return 10;} @@ -85,6 +94,11 @@ DexItemFactory factory = appView.dexItemFactory(); List<CfInstruction> instructions = new ArrayList<>(); + ImmutableInt2ReferenceSortedMap<FrameType> locals = + ImmutableInt2ReferenceSortedMap.<FrameType>builder() + .put(0, FrameType.initialized(factory.intType)) + .build(); + // if (i == 1) { return 10;} // if (i == 2) { return 20;} enumValueInfoMap.forEach( @@ -98,12 +112,19 @@ addCfInstructionsForAbstractValue(instructions, value, returnType); instructions.add(new CfReturn(ValueType.fromDexType(returnType))); instructions.add(dest); + instructions.add(new CfFrame(locals, ImmutableList.of())); } }); - // throw null; - instructions.add(new CfConstNull()); - instructions.add(new CfThrow()); + if (nullValue != null) { + // return "null" + addCfInstructionsForAbstractValue(instructions, nullValue, returnType); + instructions.add(new CfReturn(ValueType.fromDexType(returnType))); + } else { + // throw null; + instructions.add(new CfConstNull()); + instructions.add(new CfThrow()); + } return standardCfCodeFromInstructions(instructions); } @@ -139,6 +160,11 @@ DexItemFactory factory = appView.dexItemFactory(); List<CfInstruction> instructions = new ArrayList<>(); + ImmutableInt2ReferenceSortedMap<FrameType> locals = + ImmutableInt2ReferenceSortedMap.<FrameType>builder() + .put(0, FrameType.initialized(factory.stringType)) + .build(); + // if (s == null) { throw npe("Name is null"); } CfLabel nullDest = new CfLabel(); instructions.add(new CfLoad(ValueType.fromDexType(factory.stringType), 0)); @@ -150,6 +176,7 @@ new CfInvoke(Opcodes.INVOKESPECIAL, factory.npeMethods.initWithMessage, false)); instructions.add(new CfThrow()); instructions.add(nullDest); + instructions.add(new CfFrame(locals, ImmutableList.of())); // if (s.equals("A")) { return 1;} // if (s.equals("B")) { return 2;} @@ -165,6 +192,7 @@ instructions.add(new CfConstNumber(enumValueInfo.convertToInt(), ValueType.INT)); instructions.add(new CfReturn(ValueType.INT)); instructions.add(dest); + instructions.add(new CfFrame(locals, ImmutableList.of())); }); // throw new IllegalArgumentException("No enum constant com.x.MyEnum." + s); @@ -225,6 +253,9 @@ instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, initializationMethod, false)); instructions.add(new CfFieldInstruction(Opcodes.PUTSTATIC, utilityField, utilityField)); instructions.add(nullDest); + instructions.add( + new CfFrame( + ImmutableInt2ReferenceSortedMap.<FrameType>builder().build(), ImmutableList.of())); instructions.add(new CfFieldInstruction(Opcodes.GETSTATIC, utilityField, utilityField)); instructions.add(new CfReturn(ValueType.OBJECT)); return standardCfCodeFromInstructions(instructions);
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java index 8c895f7..ec34d75 100644 --- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -16,6 +16,7 @@ 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.CfCode; import com.android.tools.r8.graph.DexAnnotation; import com.android.tools.r8.graph.DexAnnotationElement; import com.android.tools.r8.graph.DexAnnotationSet; @@ -36,6 +37,8 @@ import com.android.tools.r8.graph.InnerClassAttribute; import com.android.tools.r8.graph.NestMemberClassAttribute; import com.android.tools.r8.graph.ParameterAnnotationsList; +import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.naming.ProguardMapSupplier; import com.android.tools.r8.references.Reference; @@ -108,12 +111,13 @@ } Optional<String> markerString = marker.isRelocator() ? Optional.empty() : Optional.of(marker.toString()); + LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView); for (DexProgramClass clazz : application.classes()) { if (clazz.getSynthesizedFrom().isEmpty() || options.isDesugaredLibraryCompilation() || options.cfToCfDesugar) { try { - writeClass(clazz, consumer, markerString); + writeClass(clazz, consumer, rewriter, markerString); } catch (ClassTooLargeException e) { throw appView .options() @@ -145,7 +149,10 @@ } private void writeClass( - DexProgramClass clazz, ClassFileConsumer consumer, Optional<String> markerString) { + DexProgramClass clazz, + ClassFileConsumer consumer, + LensCodeRewriterUtils rewriter, + Optional<String> markerString) { ClassWriter writer = new ClassWriter(0); if (markerString.isPresent()) { int markerStringPoolIndex = writer.newConst(markerString.get()); @@ -194,12 +201,7 @@ for (DexEncodedField field : clazz.instanceFields()) { writeField(field, writer); } - for (DexEncodedMethod method : clazz.directMethods()) { - writeMethod(method, writer, defaults, version); - } - for (DexEncodedMethod method : clazz.virtualMethods()) { - writeMethod(method, writer, defaults, version); - } + clazz.forEachProgramMethod(method -> writeMethod(method, version, rewriter, writer, defaults)); writer.visitEnd(); byte[] result = writer.toByteArray(); @@ -323,28 +325,30 @@ } private void writeMethod( - DexEncodedMethod method, + ProgramMethod method, + int classFileVersion, + LensCodeRewriterUtils rewriter, ClassWriter writer, - ImmutableMap<DexString, DexValue> defaults, - int classFileVersion) { - int access = method.accessFlags.getAsCfAccessFlags(); - String name = namingLens.lookupName(method.method).toString(); - String desc = method.descriptor(namingLens); - String signature = getSignature(method.annotations()); - String[] exceptions = getExceptions(method.annotations()); + ImmutableMap<DexString, DexValue> defaults) { + DexEncodedMethod definition = method.getDefinition(); + int access = definition.getAccessFlags().getAsCfAccessFlags(); + String name = namingLens.lookupName(method.getReference()).toString(); + String desc = definition.descriptor(namingLens); + String signature = getSignature(definition.annotations()); + String[] exceptions = getExceptions(definition.annotations()); MethodVisitor visitor = writer.visitMethod(access, name, desc, signature, exceptions); - if (defaults.containsKey(method.method.name)) { + if (defaults.containsKey(definition.getName())) { AnnotationVisitor defaultVisitor = visitor.visitAnnotationDefault(); if (defaultVisitor != null) { - writeAnnotationElement(defaultVisitor, null, defaults.get(method.method.name)); + writeAnnotationElement(defaultVisitor, null, defaults.get(definition.getName())); defaultVisitor.visitEnd(); } } - writeMethodParametersAnnotation(visitor, method.annotations().annotations); - writeAnnotations(visitor::visitAnnotation, method.annotations().annotations); - writeParameterAnnotations(visitor, method.parameterAnnotationsList); - if (!method.shouldNotHaveCode()) { - writeCode(method, visitor, classFileVersion); + writeMethodParametersAnnotation(visitor, definition.annotations().annotations); + writeAnnotations(visitor::visitAnnotation, definition.annotations().annotations); + writeParameterAnnotations(visitor, definition.parameterAnnotationsList); + if (!definition.shouldNotHaveCode()) { + writeCode(method, classFileVersion, rewriter, visitor); } visitor.visitEnd(); } @@ -478,8 +482,13 @@ } } - private void writeCode(DexEncodedMethod method, MethodVisitor visitor, int classFileVersion) { - method.getCode().asCfCode().write(method, visitor, namingLens, appView, classFileVersion); + private void writeCode( + ProgramMethod method, + int classFileVersion, + LensCodeRewriterUtils rewriter, + MethodVisitor visitor) { + CfCode code = method.getDefinition().getCode().asCfCode(); + code.write(method, classFileVersion, appView, namingLens, rewriter, visitor); } public static String printCf(byte[] result) {
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 05c6f6c..6c6bab5 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -28,7 +28,6 @@ import com.android.tools.r8.graph.FieldAccessInfo; import com.android.tools.r8.graph.FieldAccessInfoCollection; 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.GraphLens; import com.android.tools.r8.graph.GraphLens.NestedGraphLens; @@ -118,7 +117,7 @@ * a given field is read/written by the program, and it also includes all indirect accesses to * each field. The latter is used, for example, during member rebinding. */ - private final FieldAccessInfoCollectionImpl fieldAccessInfoCollection; + private FieldAccessInfoCollectionImpl fieldAccessInfoCollection; /** Information about instantiated classes and their allocation sites. */ private final ObjectAllocationInfoCollectionImpl objectAllocationInfoCollection; /** Set of all methods referenced in virtual invokes, along with calling context. */ @@ -197,6 +196,7 @@ // TODO(zerny): Clean up the constructors so we have just one. AppInfoWithLiveness( DirectMappedDexApplication application, + MainDexClasses mainDexClasses, SyntheticItems.CommittedItems syntheticItems, Set<DexType> deadProtoTypes, Set<DexType> missingTypes, @@ -238,7 +238,7 @@ EnumValueInfoMapCollection enumValueInfoMaps, Set<DexType> constClassReferences, Map<DexType, Visibility> initClassReferences) { - super(application, syntheticItems); + super(application, mainDexClasses, syntheticItems); this.deadProtoTypes = deadProtoTypes; this.missingTypes = missingTypes; this.liveTypes = liveTypes; @@ -325,6 +325,7 @@ Map<DexType, Visibility> initClassReferences) { super( appInfoWithClassHierarchy.app(), + appInfoWithClassHierarchy.getMainDexClasses(), appInfoWithClassHierarchy.getSyntheticItems().commit(appInfoWithClassHierarchy.app())); this.deadProtoTypes = deadProtoTypes; this.missingTypes = missingTypes; @@ -420,6 +421,7 @@ Collection<DexReference> additionalPinnedItems) { this( application, + previous.getMainDexClasses(), previous.getSyntheticItems().commit(application), previous.deadProtoTypes, previous.missingTypes, @@ -507,7 +509,10 @@ AppInfoWithLiveness previous, Map<DexField, Int2ReferenceMap<DexField>> switchMaps, EnumValueInfoMapCollection enumValueInfoMaps) { - super(previous.app(), previous.getSyntheticItems().commit(previous.app())); + super( + previous.app(), + previous.getMainDexClasses(), + previous.getSyntheticItems().commit(previous.app())); this.deadProtoTypes = previous.deadProtoTypes; this.missingTypes = previous.missingTypes; this.liveTypes = previous.liveTypes; @@ -715,25 +720,6 @@ return constClassReferences.contains(type); } - public AppInfoWithLiveness withoutStaticFieldsWrites(Set<DexField> noLongerWrittenFields) { - assert checkIfObsolete(); - if (noLongerWrittenFields.isEmpty()) { - return this; - } - AppInfoWithLiveness result = new AppInfoWithLiveness(this); - result.fieldAccessInfoCollection.forEach( - info -> { - if (noLongerWrittenFields.contains(info.getField())) { - // Note that this implicitly mutates the current AppInfoWithLiveness, since the `info` - // instance is shared between the old and the new AppInfoWithLiveness. This should not - // lead to any problems, though, since the new AppInfo replaces the old AppInfo (we - // never use an obsolete AppInfo). - info.clearWrites(); - } - }); - return result; - } - public Set<DexType> getDeadProtoTypes() { return deadProtoTypes; } @@ -810,7 +796,7 @@ public boolean isFieldRead(DexEncodedField encodedField) { assert checkIfObsolete(); DexField field = encodedField.field; - FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field); + FieldAccessInfo info = getFieldAccessInfoCollection().get(field); if (info != null && info.isRead()) { return true; } @@ -834,7 +820,7 @@ public boolean isFieldWrittenByFieldPutInstruction(DexEncodedField encodedField) { assert checkIfObsolete(); DexField field = encodedField.field; - FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field); + FieldAccessInfo info = getFieldAccessInfoCollection().get(field); if (info != null && info.isWritten()) { // The field is written directly by the program itself. return true; @@ -850,13 +836,13 @@ public boolean isFieldOnlyWrittenInMethod(DexEncodedField field, DexEncodedMethod method) { assert checkIfObsolete(); assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written"; - if (!isPinned(field.field)) { - FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field); - return fieldAccessInfo != null - && fieldAccessInfo.isWritten() - && !fieldAccessInfo.isWrittenOutside(method); + if (isPinned(field.field)) { + return false; } - return false; + FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field); + return fieldAccessInfo != null + && fieldAccessInfo.isWritten() + && !fieldAccessInfo.isWrittenOutside(method); } public boolean isInstanceFieldWrittenOnlyInInstanceInitializers(DexEncodedField field) { @@ -865,7 +851,7 @@ if (isPinned(field.field)) { return false; } - FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field); + FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field); if (fieldAccessInfo == null || !fieldAccessInfo.isWritten()) { return false; } @@ -1004,6 +990,7 @@ DexDefinitionSupplier definitionSupplier = application.getDefinitionsSupplier(committedItems); return new AppInfoWithLiveness( application, + getMainDexClasses().rewrittenWithLens(lens), committedItems, deadProtoTypes, missingTypes, @@ -1015,7 +1002,9 @@ lens.rewriteMethods(methodsTargetedByInvokeDynamic), lens.rewriteMethods(virtualMethodsTargetedByInvokeDirect), lens.rewriteMethods(liveMethods), - fieldAccessInfoCollection.rewrittenWithLens(definitionSupplier, lens), + fieldAccessInfoCollection != null + ? fieldAccessInfoCollection.rewrittenWithLens(definitionSupplier, lens) + : null, objectAllocationInfoCollection.rewrittenWithLens(definitionSupplier, lens), rewriteInvokesWithContexts(virtualInvokes, lens), rewriteInvokesWithContexts(interfaceInvokes, lens),
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 ac6bad1..d692cef 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2792,7 +2792,7 @@ new ArrayList<>(); // Subset of synthesized classes that need to be added to the main-dex file. - Set<DexType> mainDexTypes = Sets.newIdentityHashSet(); + Set<DexProgramClass> mainDexTypes = Sets.newIdentityHashSet(); boolean isEmpty() { boolean empty = @@ -2808,7 +2808,7 @@ assert !syntheticInstantiations.containsKey(clazz.type); syntheticInstantiations.put(clazz.type, new Pair<>(clazz, context)); if (isMainDexClass) { - mainDexTypes.add(clazz.type); + mainDexTypes.add(clazz); } } @@ -2836,7 +2836,11 @@ appBuilder.addProgramClass(clazzAndContext.getFirst()); } appBuilder.addClasspathClasses(syntheticClasspathClasses.values()); - appBuilder.addToMainDexList(mainDexTypes); + } + + void amendMainDexClasses(MainDexClasses mainDexClasses) { + assert !isEmpty(); + mainDexClasses.addAll(mainDexTypes); } void enqueueWorkItems(Enqueuer enqueuer) { @@ -2887,6 +2891,7 @@ additions.amendApplication(appBuilder); return appBuilder.build(); }); + additions.amendMainDexClasses(appInfo.getMainDexClasses()); appView.setAppInfo(appInfo); subtypingInfo = new SubtypingInfo(appView); @@ -3015,6 +3020,7 @@ AppInfoWithLiveness appInfoWithLiveness = new AppInfoWithLiveness( app, + appInfo.getMainDexClasses(), appInfo.getSyntheticItems().commit(app), deadProtoTypes, mode.isFinalTreeShaking()
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java index c21ce6c..cfadae32 100644 --- a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java +++ b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
@@ -1,115 +1,100 @@ -// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file +// 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.shaking; -import com.android.tools.r8.graph.AppInfo; -import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; -import com.google.common.collect.ImmutableSet; +import com.android.tools.r8.graph.GraphLens; import com.google.common.collect.Sets; -import java.util.Collection; -import java.util.Collections; import java.util.Set; import java.util.function.Consumer; -import java.util.function.Predicate; public class MainDexClasses { - public static MainDexClasses NONE = new MainDexClasses(ImmutableSet.of(), ImmutableSet.of()); + private final Set<DexType> mainDexClasses; - public static class Builder { - public final AppInfo appInfo; - public final Set<DexType> roots = Sets.newIdentityHashSet(); - public final Set<DexType> dependencies = Sets.newIdentityHashSet(); + private MainDexClasses() { + this(Sets.newIdentityHashSet()); + } - private Builder(AppInfo appInfo) { - this.appInfo = appInfo; - } + private MainDexClasses(Set<DexType> mainDexClasses) { + this.mainDexClasses = mainDexClasses; + } - public Builder addRoot(DexType type) { - assert isProgramClass(type) : type.toSourceString(); - roots.add(type); - return this; - } + public static Builder builder() { + return new Builder(); + } - public Builder addRoots(Collection<DexType> rootSet) { - assert rootSet.stream().allMatch(this::isProgramClass); - this.roots.addAll(rootSet); - return this; - } + public static MainDexClasses createEmptyMainDexClasses() { + return new MainDexClasses(); + } - public Builder addDependency(DexType type) { - assert isProgramClass(type); - dependencies.add(type); - return this; - } + public void add(DexProgramClass clazz) { + mainDexClasses.add(clazz.getType()); + } - public boolean contains(DexType type) { - return roots.contains(type) || dependencies.contains(type); - } + public void addAll(MainDexClasses other) { + mainDexClasses.addAll(other.mainDexClasses); + } - public MainDexClasses build() { - return new MainDexClasses(roots, dependencies); - } + public void addAll(MainDexTracingResult other) { + mainDexClasses.addAll(other.getClasses()); + } - private boolean isProgramClass(DexType dexType) { - DexClass clazz = appInfo.definitionFor(dexType); - return clazz != null && clazz.isProgramClass(); + public void addAll(Iterable<DexProgramClass> classes) { + for (DexProgramClass clazz : classes) { + add(clazz); } } - // The classes in the root set. - private final Set<DexType> roots; - // Additional dependencies (direct dependencies and runtime annotations with enums). - private final Set<DexType> dependencies; - // All main dex classes. - private final Set<DexType> classes; + public boolean contains(DexProgramClass clazz) { + return mainDexClasses.contains(clazz.getType()); + } - private MainDexClasses(Set<DexType> roots, Set<DexType> dependencies) { - assert Sets.intersection(roots, dependencies).isEmpty(); - this.roots = Collections.unmodifiableSet(roots); - this.dependencies = Collections.unmodifiableSet(dependencies); - this.classes = Sets.union(roots, dependencies); + public boolean containsAnyOf(Iterable<DexProgramClass> classes) { + for (DexProgramClass clazz : classes) { + if (contains(clazz)) { + return true; + } + } + return false; + } + + public void forEach(Consumer<DexType> fn) { + mainDexClasses.forEach(fn); } public boolean isEmpty() { - assert !roots.isEmpty() || dependencies.isEmpty(); - return roots.isEmpty(); + return mainDexClasses.isEmpty(); } - public Set<DexType> getRoots() { - return roots; + public MainDexClasses rewrittenWithLens(GraphLens lens) { + MainDexClasses rewrittenMainDexClasses = createEmptyMainDexClasses(); + for (DexType mainDexClass : mainDexClasses) { + DexType rewrittenMainDexClass = lens.lookupType(mainDexClass); + rewrittenMainDexClasses.mainDexClasses.add(rewrittenMainDexClass); + } + return rewrittenMainDexClasses; } - public Set<DexType> getDependencies() { - return dependencies; + public int size() { + return mainDexClasses.size(); } - public Set<DexType> getClasses() { - return classes; - } + public static class Builder { - private void collectTypesMatching( - Set<DexType> types, Predicate<DexType> predicate, Consumer<DexType> consumer) { - types.forEach( - type -> { - if (predicate.test(type)) { - consumer.accept(type); - } - }); - } + private final Set<DexType> mainDexClasses = Sets.newIdentityHashSet(); - public MainDexClasses prunedCopy(AppInfoWithLiveness appInfo) { - Builder builder = builder(appInfo); - Predicate<DexType> wasPruned = appInfo::wasPruned; - collectTypesMatching(roots, wasPruned.negate(), builder::addRoot); - collectTypesMatching(dependencies, wasPruned.negate(), builder::addDependency); - return builder.build(); - } + private Builder() {} - public static Builder builder(AppInfo appInfo) { - return new Builder(appInfo); + public void add(DexProgramClass clazz) { + mainDexClasses.add(clazz.getType()); + } + + public MainDexClasses build() { + return new MainDexClasses(mainDexClasses); + } } }
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java index c122cd7..4fa5d3a 100644 --- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java +++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -30,7 +30,7 @@ private final Set<DexType> roots; private final AppView<? extends AppInfoWithClassHierarchy> appView; private final Map<DexType, Boolean> annotationTypeContainEnum; - private final MainDexClasses.Builder mainDexClassesBuilder; + private final MainDexTracingResult.Builder mainDexClassesBuilder; public static void checkForAssumedLibraryTypes(AppInfo appInfo) { DexClass enumType = appInfo.definitionFor(appInfo.dexItemFactory().enumType); @@ -54,7 +54,7 @@ this.appView = appView; // Only consider program classes for the root set. this.roots = SetUtils.mapIdentityHashSet(roots, DexProgramClass::getType); - mainDexClassesBuilder = MainDexClasses.builder(appView.appInfo()).addRoots(this.roots); + mainDexClassesBuilder = MainDexTracingResult.builder(appView.appInfo()).addRoots(this.roots); annotationTypeContainEnum = new IdentityHashMap<>(); } @@ -62,7 +62,7 @@ return appView.appInfo(); } - public MainDexClasses run() { + public MainDexTracingResult run() { traceMainDexDirectDependencies(); traceRuntimeAnnotationsWithEnumForMainDex(); return mainDexClassesBuilder.build();
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexTracingResult.java b/src/main/java/com/android/tools/r8/shaking/MainDexTracingResult.java new file mode 100644 index 0000000..d333211 --- /dev/null +++ b/src/main/java/com/android/tools/r8/shaking/MainDexTracingResult.java
@@ -0,0 +1,116 @@ +// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.shaking; + +import com.android.tools.r8.graph.AppInfo; +import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexType; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class MainDexTracingResult { + + public static MainDexTracingResult NONE = + new MainDexTracingResult(ImmutableSet.of(), ImmutableSet.of()); + + public static class Builder { + public final AppInfo appInfo; + public final Set<DexType> roots = Sets.newIdentityHashSet(); + public final Set<DexType> dependencies = Sets.newIdentityHashSet(); + + private Builder(AppInfo appInfo) { + this.appInfo = appInfo; + } + + public Builder addRoot(DexType type) { + assert isProgramClass(type) : type.toSourceString(); + roots.add(type); + return this; + } + + public Builder addRoots(Collection<DexType> rootSet) { + assert rootSet.stream().allMatch(this::isProgramClass); + this.roots.addAll(rootSet); + return this; + } + + public Builder addDependency(DexType type) { + assert isProgramClass(type); + dependencies.add(type); + return this; + } + + public boolean contains(DexType type) { + return roots.contains(type) || dependencies.contains(type); + } + + public MainDexTracingResult build() { + return new MainDexTracingResult(roots, dependencies); + } + + private boolean isProgramClass(DexType dexType) { + DexClass clazz = appInfo.definitionFor(dexType); + return clazz != null && clazz.isProgramClass(); + } + } + + // The classes in the root set. + private final Set<DexType> roots; + // Additional dependencies (direct dependencies and runtime annotations with enums). + private final Set<DexType> dependencies; + // All main dex classes. + private final Set<DexType> classes; + + private MainDexTracingResult(Set<DexType> roots, Set<DexType> dependencies) { + assert Sets.intersection(roots, dependencies).isEmpty(); + this.roots = Collections.unmodifiableSet(roots); + this.dependencies = Collections.unmodifiableSet(dependencies); + this.classes = Sets.union(roots, dependencies); + } + + public boolean isEmpty() { + assert !roots.isEmpty() || dependencies.isEmpty(); + return roots.isEmpty(); + } + + public Set<DexType> getRoots() { + return roots; + } + + public Set<DexType> getDependencies() { + return dependencies; + } + + public Set<DexType> getClasses() { + return classes; + } + + private void collectTypesMatching( + Set<DexType> types, Predicate<DexType> predicate, Consumer<DexType> consumer) { + types.forEach( + type -> { + if (predicate.test(type)) { + consumer.accept(type); + } + }); + } + + public MainDexTracingResult prunedCopy(AppInfoWithLiveness appInfo) { + Builder builder = builder(appInfo); + Predicate<DexType> wasPruned = appInfo::wasPruned; + collectTypesMatching(roots, wasPruned.negate(), builder::addRoot); + collectTypesMatching(dependencies, wasPruned.negate(), builder::addDependency); + return builder.build(); + } + + public static Builder builder(AppInfo appInfo) { + return new Builder(appInfo); + } +}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java index 1b51a73..6b5604e 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -51,6 +51,9 @@ private final Reporter reporter; private final boolean allowTestOptions; + public static final String FLATTEN_PACKAGE_HIERARCHY = "flattenpackagehierarchy"; + public static final String REPACKAGE_CLASSES = "repackageclasses"; + private static final List<String> IGNORED_SINGLE_ARG_OPTIONS = ImmutableList.of( "protomapping", "target",
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java index 0d803ea..3725f5f 100644 --- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -187,7 +187,7 @@ } private final AppView<AppInfoWithLiveness> appView; - private final MainDexClasses mainDexClasses; + private final MainDexTracingResult mainDexClasses; /** The equivalence that should be used for the member buckets in {@link Representative}. */ private final Equivalence<DexField> fieldEquivalence; @@ -203,7 +203,7 @@ public StaticClassMerger( AppView<AppInfoWithLiveness> appView, InternalOptions options, - MainDexClasses mainDexClasses) { + MainDexTracingResult mainDexClasses) { this.appView = appView; if (options.getProguardConfiguration().isOverloadAggressively()) { fieldEquivalence = FieldSignatureEquivalence.getEquivalenceIgnoreName();
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 17cf952..2d21927 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -217,14 +217,14 @@ // All the bridge methods that have been synthesized during vertical class merging. private final List<SynthesizedBridgeCode> synthesizedBridges = new ArrayList<>(); - private final MainDexClasses mainDexClasses; + private final MainDexTracingResult mainDexClasses; public VerticalClassMerger( DexApplication application, AppView<AppInfoWithLiveness> appView, ExecutorService executorService, Timing timing, - MainDexClasses mainDexClasses) { + MainDexTracingResult mainDexClasses) { this.application = application; this.appInfo = appView.appInfo(); this.appView = appView;
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 7f54137..a9d5c3d 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -491,6 +491,10 @@ private final boolean enableTreeShaking; private final boolean enableMinification; + public boolean isRelease() { + return !debug; + } + public boolean isShrinking() { assert proguardConfiguration == null || enableTreeShaking == proguardConfiguration.isShrinking();
diff --git a/src/main/java/com/android/tools/r8/utils/MainDexList.java b/src/main/java/com/android/tools/r8/utils/MainDexListParser.java similarity index 93% rename from src/main/java/com/android/tools/r8/utils/MainDexList.java rename to src/main/java/com/android/tools/r8/utils/MainDexListParser.java index e323566..136ae2a 100644 --- a/src/main/java/com/android/tools/r8/utils/MainDexList.java +++ b/src/main/java/com/android/tools/r8/utils/MainDexListParser.java
@@ -15,7 +15,7 @@ import com.google.common.collect.Sets; import java.util.Set; -public class MainDexList { +public class MainDexListParser { public static DexType parseEntry(String clazz, DexItemFactory itemFactory) { if (!clazz.endsWith(CLASS_EXTENSION)) { @@ -47,7 +47,10 @@ try { result.add(parseEntry(line, itemFactory)); } catch (CompilationError e) { - throw new CompilationError(e.getMessage(), e, resource.getOrigin(), + throw new CompilationError( + e.getMessage(), + e, + resource.getOrigin(), new TextPosition(offset, lineNumber, TextPosition.UNKNOWN_COLUMN)); } }
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java index dd5b43a..68fa8f3 100644 --- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java +++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -82,7 +82,7 @@ private static DexProgramClass mergeClasses( Reporter reporter, DexProgramClass a, DexProgramClass b) { - if (a.type.isD8R8SynthesizedClassType()) { + if (a.type.isLegacySynthesizedTypeAllowedDuplication()) { assert assertEqualClasses(a, b); return a; }
diff --git a/src/main/java/com/android/tools/r8/utils/WorkList.java b/src/main/java/com/android/tools/r8/utils/WorkList.java index e9bf6cd..2e74be4 100644 --- a/src/main/java/com/android/tools/r8/utils/WorkList.java +++ b/src/main/java/com/android/tools/r8/utils/WorkList.java
@@ -76,6 +76,10 @@ return !workingList.isEmpty(); } + public boolean isEmpty() { + return !hasNext(); + } + public void markAsSeen(T item) { seen.add(item); }
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ImmutableInt2ReferenceSortedMap.java b/src/main/java/com/android/tools/r8/utils/collections/ImmutableInt2ReferenceSortedMap.java new file mode 100644 index 0000000..af41bf1 --- /dev/null +++ b/src/main/java/com/android/tools/r8/utils/collections/ImmutableInt2ReferenceSortedMap.java
@@ -0,0 +1,190 @@ +// 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.errors.Unreachable; +import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMaps; +import it.unimi.dsi.fastutil.ints.IntSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; +import org.jetbrains.annotations.Nullable; + +public class ImmutableInt2ReferenceSortedMap<V> extends Int2ReferenceSortedMaps.EmptySortedMap<V> { + + private final Int2ReferenceSortedMap<V> sortedMap; + + private ImmutableInt2ReferenceSortedMap(Int2ReferenceSortedMap<V> sortedMap) { + this.sortedMap = sortedMap; + } + + public static <V> ImmutableInt2ReferenceSortedMap<V> of(Int2ReferenceSortedMap<V> sortedMap) { + return new ImmutableInt2ReferenceSortedMap<>(sortedMap); + } + + public static <V> ImmutableInt2ReferenceSortedMap<V> of(int[] keys, V[] values) { + return new ImmutableInt2ReferenceSortedMap<>(new Int2ReferenceAVLTreeMap<>(keys, values)); + } + + public static <V> Builder<V> builder() { + return new Builder<>(); + } + + public static class Builder<V> { + + private final Int2ReferenceSortedMap<V> sortedMap = new Int2ReferenceAVLTreeMap<>(); + + public Builder<V> put(int k, V v) { + sortedMap.put(k, v); + return this; + } + + public ImmutableInt2ReferenceSortedMap<V> build() { + return new ImmutableInt2ReferenceSortedMap<>(sortedMap); + } + } + + @Override + public int size() { + return sortedMap.size(); + } + + @SuppressWarnings("unchecked") + @Override + public ObjectSortedSet<Entry<V>> int2ReferenceEntrySet() { + return sortedMap.int2ReferenceEntrySet(); + } + + @Deprecated + @Override + @SuppressWarnings("unchecked") + public ObjectSortedSet<Map.Entry<Integer, V>> entrySet() { + return sortedMap.entrySet(); + } + + @Override + public IntSortedSet keySet() { + return sortedMap.keySet(); + } + + @SuppressWarnings("unchecked") + @Override + public Int2ReferenceSortedMap<V> subMap(final int from, final int to) { + return sortedMap.subMap(from, to); + } + + @SuppressWarnings("unchecked") + @Override + public Int2ReferenceSortedMap<V> headMap(final int to) { + return sortedMap.headMap(to); + } + + @SuppressWarnings("unchecked") + @Override + public Int2ReferenceSortedMap<V> tailMap(final int from) { + return sortedMap.tailMap(from); + } + + @Override + public boolean isEmpty() { + return sortedMap.isEmpty(); + } + + @Override + public int firstIntKey() { + return sortedMap.firstIntKey(); + } + + @Override + public int lastIntKey() { + return sortedMap.lastIntKey(); + } + + @Deprecated + @Override + public Int2ReferenceSortedMap<V> headMap(Integer oto) { + return sortedMap.headMap(oto); + } + + @Deprecated + @Override + public Int2ReferenceSortedMap<V> tailMap(Integer ofrom) { + return sortedMap.tailMap(ofrom); + } + + @Deprecated + @Override + public Int2ReferenceSortedMap<V> subMap(Integer ofrom, Integer oto) { + return sortedMap.subMap(ofrom, oto); + } + + @Deprecated + @Override + public Integer firstKey() { + return sortedMap.firstKey(); + } + + @Deprecated + @Override + public Integer lastKey() { + return sortedMap.lastKey(); + } + + @Override + public V put(int key, V value) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public V put(Integer ok, V ov) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public void putAll(Map<? extends Integer, ? extends V> m) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Nullable + @Override + public V putIfAbsent(Integer key, V value) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public V compute( + Integer key, BiFunction<? super Integer, ? super V, ? extends V> remappingFunction) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public V computeIfAbsent(Integer key, Function<? super Integer, ? extends V> mappingFunction) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public V computeIfPresent( + Integer key, BiFunction<? super Integer, ? super V, ? extends V> remappingFunction) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public V remove(int key) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public boolean remove(Object key, Object value) { + throw new Unreachable("Should not modify an immutable structure"); + } + + @Override + public V remove(Object ok) { + throw new Unreachable("Should not modify an immutable structure"); + } +}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java index 92d51ea..0732bcb 100644 --- a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java +++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
@@ -15,6 +15,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; @@ -50,6 +51,10 @@ return new ProgramMethodSet(new LinkedHashMap<>()); } + public static ProgramMethodSet createSorted() { + return new ProgramMethodSet(new TreeMap<>(DexMethod::slowCompareTo)); + } + public static ProgramMethodSet empty() { return EMPTY; }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java index 9aa9789..342920c 100644 --- a/src/test/java/com/android/tools/r8/TestBase.java +++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -44,6 +44,7 @@ import com.android.tools.r8.references.TypeReference; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.EnqueuerFactory; +import com.android.tools.r8.shaking.MainDexClasses; import com.android.tools.r8.shaking.ProguardClassFilter; import com.android.tools.r8.shaking.ProguardClassNameList; import com.android.tools.r8.shaking.ProguardConfiguration; @@ -650,7 +651,8 @@ protected static AppInfoWithClassHierarchy computeAppInfoWithClassHierarchy(AndroidApp app) throws Exception { return AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy( - readApplicationForDexOutput(app, new InternalOptions())); + readApplicationForDexOutput(app, new InternalOptions()), + MainDexClasses.createEmptyMainDexClasses()); } protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithSubtyping(AndroidApp app) @@ -1601,6 +1603,10 @@ return AndroidApiLevel.O; } + public static AndroidApiLevel apiLevelWithNativeMultiDexSupport() { + return AndroidApiLevel.L; + } + public Path compileToZip( TestParameters parameters, Collection<Class<?>> classPath, Class<?>... compilationUnit) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java index 226af98..b2e1d59 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
@@ -5,14 +5,21 @@ package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static com.android.tools.r8.utils.codeinspector.Matchers.readsInstanceField; +import static com.android.tools.r8.utils.codeinspector.Matchers.writesInstanceField; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsNot.not; import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestParameters; import com.android.tools.r8.classmerging.horizontal.ConstructorMergingTest.A; import com.android.tools.r8.classmerging.horizontal.ConstructorMergingTest.B; import com.android.tools.r8.classmerging.horizontal.ConstructorMergingTest.Main; +import com.android.tools.r8.horizontalclassmerging.ClassMerger; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.FieldSubject; +import com.android.tools.r8.utils.codeinspector.MethodSubject; import org.junit.Test; public class MergedConstructorForwardingTest extends HorizontalClassMergingTestBase { @@ -29,15 +36,37 @@ .addKeepMainRule(Main.class) .addOptionsModification( options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging) + .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) - .assertSuccessWithOutputLines("42", "13", "21", "39") + .assertSuccessWithOutputLines("42", "13", "21", "39", "print a", "print b") .inspect( codeInspector -> { if (enableHorizontalClassMerging) { - assertThat(codeInspector.clazz(A.class), isPresent()); + ClassSubject aClassSubject = codeInspector.clazz(A.class); + assertThat(aClassSubject, isPresent()); + FieldSubject classIdFieldSubject = + aClassSubject.uniqueFieldWithName(ClassMerger.CLASS_ID_FIELD_NAME); + assertThat(classIdFieldSubject, isPresent()); + + MethodSubject firstInitSubject = aClassSubject.init("int"); + assertThat(firstInitSubject, isPresent()); + assertThat( + firstInitSubject, writesInstanceField(classIdFieldSubject.getFieldReference())); + + MethodSubject otherInitSubject = aClassSubject.init("long", "int"); + assertThat(otherInitSubject, isPresent()); + assertThat( + otherInitSubject, writesInstanceField(classIdFieldSubject.getFieldReference())); + + MethodSubject printSubject = aClassSubject.method("void", "print"); + assertThat(printSubject, isPresent()); + assertThat( + printSubject, readsInstanceField(classIdFieldSubject.getFieldReference())); + assertThat(codeInspector.clazz(B.class), not(isPresent())); + // TODO(b/165517236): Explicitly check classes have been merged. } else { assertThat(codeInspector.clazz(A.class), isPresent()); @@ -55,6 +84,11 @@ public A(long x) { System.out.println(x); } + + @NeverInline + public void print() { + System.out.println("print a"); + } } @NeverClassInline @@ -66,6 +100,11 @@ public B(long y) { System.out.println(y * 3); } + + @NeverInline + public void print() { + System.out.println("print b"); + } } public static class Main { @@ -74,6 +113,8 @@ a = new A(13); B b = new B(); b = new B(13); + a.print(); + b.print(); } } }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java new file mode 100644 index 0000000..1f0daeb --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -0,0 +1,105 @@ +// 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.classmerging.horizontal; + +import static com.android.tools.r8.naming.retrace.StackTrace.isSame; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverMerge; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestRuntime.CfRuntime; +import com.android.tools.r8.naming.retrace.StackTrace; +import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine; +import org.junit.Before; +import org.junit.Test; + +public class MergedConstructorStackTraceTest extends HorizontalClassMergingTestBase { + + public StackTrace expectedStackTrace; + + public MergedConstructorStackTraceTest( + TestParameters parameters, boolean enableHorizontalClassMerging) { + super(parameters, enableHorizontalClassMerging); + } + + @Before + public void setup() throws Exception { + // Get the expected stack trace by running on the JVM. + expectedStackTrace = + testForJvm() + .addTestClasspath() + .run(CfRuntime.getSystemRuntime(), Main.class) + .assertFailure() + .map(StackTrace::extractFromJvm); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepAttributeLineNumberTable() + .addKeepAttributeSourceFile() + .addOptionsModification( + options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging) + .enableMergeAnnotations() + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), Main.class) + .inspectStackTrace( + (stackTrace, codeInspector) -> { + assertThat(codeInspector.clazz(A.class), isPresent()); + if (enableHorizontalClassMerging) { + StackTrace expectedStackTraceWithMergedConstructor = + StackTrace.builder() + .add(expectedStackTrace) + .add( + 2, + StackTraceLine.builder() + .setClassName(A.class.getTypeName()) + .setMethodName("<init>") + .setFileName(getClass().getSimpleName() + ".java") + .setLineNumber(0) + .build()) + .build(); + assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor)); + assertThat(codeInspector.clazz(B.class), not(isPresent())); + } else { + assertThat(stackTrace, isSame(expectedStackTrace)); + assertThat(codeInspector.clazz(B.class), isPresent()); + } + }); + } + + @NeverMerge + static class Parent { + Parent() { + if (System.currentTimeMillis() >= 0) { + throw new RuntimeException(); + } + } + } + + @NeverClassInline + static class A extends Parent { + A() {} + } + + @NeverClassInline + static class B extends Parent { + B() {} + } + + static class Main { + public static void main(String[] args) { + new A(); + new B(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java new file mode 100644 index 0000000..119913b --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
@@ -0,0 +1,94 @@ +// 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.classmerging.horizontal; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestParameters; +import org.junit.Test; + +public class SuperConstructorCallsVirtualMethodTest extends HorizontalClassMergingTestBase { + public SuperConstructorCallsVirtualMethodTest( + TestParameters parameters, boolean enableHorizontalClassMerging) { + super(parameters, enableHorizontalClassMerging); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addOptionsModification( + options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging) + .enableInliningAnnotations() + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("5", "foo hello", "B", "bar world", "5", "B") + .inspect( + codeInspector -> { + if (enableHorizontalClassMerging) { + assertThat(codeInspector.clazz(Parent.class), isPresent()); + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), not(isPresent())); + // TODO(b/165517236): Explicitly check classes have been merged. + } else { + assertThat(codeInspector.clazz(Parent.class), isPresent()); + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), isPresent()); + } + }); + } + + @NeverClassInline + public static class Parent { + String field; + + public Parent(String v) { + this.field = v; + print(); + } + + @NeverInline + public void print() { + System.out.println(field); + } + } + + @NeverClassInline + public static class A extends Parent { + public A(String arg) { + super(arg); + System.out.println("foo " + arg); + } + + @NeverInline + @Override + public void print() { + System.out.println(5); + } + } + + @NeverClassInline + public static class B extends Parent { + public B(String arg) { + super("B"); + System.out.println("bar " + arg); + } + } + + public static class Main { + public static void main(String[] args) { + A a = new A("hello"); + B b = new B("world"); + a.print(); + b.print(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodOverrideParentCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodOverrideParentCollisionTest.java new file mode 100644 index 0000000..e304a70 --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodOverrideParentCollisionTest.java
@@ -0,0 +1,92 @@ +// 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.shaking.horizontalclassmerging; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.classmerging.horizontal.HorizontalClassMergingTestBase; +import org.junit.Test; + +public class VirtualMethodOverrideParentCollisionTest extends HorizontalClassMergingTestBase { + + public VirtualMethodOverrideParentCollisionTest( + TestParameters parameters, boolean enableHorizontalClassMerging) { + super(parameters, enableHorizontalClassMerging); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(this.getClass()) + .addKeepMainRule(Main.class) + .addOptionsModification( + options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging) + .enableInliningAnnotations() + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("foo", "bar", "foo", "parent") + .inspect( + codeInspector -> { + if (enableHorizontalClassMerging) { + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), not(isPresent())); + // TODO(b/165517236): Explicitly check classes have been merged. + } else { + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), isPresent()); + } + }); + } + + @NeverClassInline + public static class Parent { + @NeverInline + public void foo() { + System.out.println("parent"); + } + } + + @NeverClassInline + public static class A extends Parent { + @NeverInline + @Override + public void foo() { + System.out.println("foo"); + } + } + + @NeverClassInline + public static class B extends Parent { + // TODO(b/164924717): remove non overlapping constructor requirement + public B(String s) {} + + @NeverInline + public void bar() { + System.out.println("bar"); + } + } + + public static class Main { + @NeverInline + static void callFoo(Parent p) { + p.foo(); + } + + public static void main(String[] args) { + A a = new A(); + a.foo(); + B b = new B(""); + b.bar(); + callFoo(a); + callFoo(b); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java new file mode 100644 index 0000000..f323ec7 --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java
@@ -0,0 +1,100 @@ +// 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.classmerging.horizontal; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NeverMerge; +import com.android.tools.r8.TestParameters; +import org.junit.Test; + +public class VirtualMethodSuperMerged extends HorizontalClassMergingTestBase { + public VirtualMethodSuperMerged(TestParameters parameters, boolean enableHorizontalClassMerging) { + super(parameters, enableHorizontalClassMerging); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(this.getClass()) + .addKeepMainRule(Main.class) + .addOptionsModification( + options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging) + .enableInliningAnnotations() + .enableNeverClassInliningAnnotations() + .enableMergeAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("foo", "parent b", "parent b", "x", "parent b") + .inspect( + codeInspector -> { + if (enableHorizontalClassMerging) { + assertThat(codeInspector.clazz(ParentA.class), isPresent()); + assertThat(codeInspector.clazz(ParentB.class), not(isPresent())); + assertThat(codeInspector.clazz(X.class), isPresent()); + assertThat(codeInspector.clazz(Y.class), not(isPresent())); + // TODO(b/165517236): Explicitly check classes have been merged. + } else { + assertThat(codeInspector.clazz(ParentA.class), isPresent()); + assertThat(codeInspector.clazz(ParentB.class), isPresent()); + assertThat(codeInspector.clazz(X.class), isPresent()); + assertThat(codeInspector.clazz(Y.class), isPresent()); + } + }); + } + + @NeverClassInline + public static class ParentA { + @NeverInline + void foo() { + System.out.println("foo"); + } + } + + @NeverMerge + @NeverClassInline + public static class ParentB { + @NeverInline + void print() { + System.out.println("parent b"); + } + } + + @NeverClassInline + public static class X extends ParentB { + public X() { + print(); + } + + @NeverInline + @Override + void print() { + super.print(); + System.out.println("x"); + } + } + + @NeverClassInline + public static class Y extends ParentB { + public Y() { + print(); + } + } + + public static class Main { + public static void main(String[] args) { + ParentA a = new ParentA(); + a.foo(); + ParentB b = new ParentB(); + b.print(); + X x = new X(); + Y y = new Y(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java index db4d3df..fa6e974 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -171,7 +171,7 @@ ToolHelper.runL8(l8Builder.build()); // Run on the JVM with desuagred library on classpath. - TestRunResult result = + TestRunResult<?> result = testForJvm() .addProgramFiles(jar) .addRunClasspathFiles(desugaredLib)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java index 2b84919..0245f6e 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -4,35 +4,82 @@ package com.android.tools.r8.desugar.desugaredlibrary; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.D8Command; +import com.android.tools.r8.DexFileMergerHelper; import com.android.tools.r8.L8; import com.android.tools.r8.L8Command; import com.android.tools.r8.OutputMode; import com.android.tools.r8.StringResource; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11DesugaredLibraryTestBase; +import com.android.tools.r8.errors.DuplicateTypesDiagnostic; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.google.common.collect.ImmutableMap; import java.nio.file.Path; 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 MergingJ$Test extends Jdk11DesugaredLibraryTestBase { + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + public MergingJ$Test(TestParameters parameters) { + parameters.assertNoneRuntime(); + } + @Test public void testMergingJ$() throws Exception { Path mergerInputPart1 = buildSplitDesugaredLibraryPart1(); Path mergerInputPart2 = buildSplitDesugaredLibraryPart2(); - CodeInspector codeInspectorOutput = null; + assertThrows( + CompilationFailedException.class, + () -> + testForD8() + .addProgramFiles(mergerInputPart1, mergerInputPart2) + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) + .compileWithExpectedDiagnostics( + diagnostics -> { + diagnostics + .assertOnlyErrors() + .assertErrorsMatch(diagnosticType(DuplicateTypesDiagnostic.class)); + })); + } + + @Test + public void testMergingJ$WithDexFileMergerHelper() throws Exception { + Path mergerInputPart1 = buildSplitDesugaredLibraryPart1(); + Path mergerInputPart2 = buildSplitDesugaredLibraryPart2(); + Path merged = temp.newFolder().toPath().resolve("merged.jar"); + D8Command command = + D8Command.builder() + .addProgramFiles(mergerInputPart1, mergerInputPart2) + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) + .setOutput(merged, OutputMode.DexIndexed) + .build(); try { - codeInspectorOutput = - testForD8() - .addProgramFiles(mergerInputPart1, mergerInputPart2) - .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) - .compile() - .inspector(); + DexFileMergerHelper.run( + command, + true, + ImmutableMap.<String, Integer>builder() + .put(mergerInputPart1.toString(), 1) + .put(mergerInputPart2.toString(), 2) + .build()); } catch (Exception e) { if (e.getCause().getMessage().contains("Merging dex file containing classes with prefix")) { // TODO(b/138278440): Forbid to merge j$ classes in a Google3 compliant way. @@ -44,6 +91,7 @@ } throw e; } + CodeInspector codeInspectorOutput = new CodeInspector(merged); CodeInspector codeInspectorSplit1 = new CodeInspector(mergerInputPart1); CodeInspector codeInspectorSplit2 = new CodeInspector(mergerInputPart2); assertNotNull(codeInspectorOutput);
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java index eeedbab..b48e0a93 100644 --- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java +++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -3,11 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.dex; +import com.android.tools.r8.graph.AppInfo; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.DexDebugEvent; import com.android.tools.r8.graph.DexDebugInfo; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexString; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.NamingLens; @@ -21,8 +23,10 @@ private ObjectToOffsetMapping emptyObjectTObjectMapping() { return new ObjectToOffsetMapping( - DexApplication.builder(new InternalOptions(new DexItemFactory(), new Reporter()), null) - .build(), + AppInfo.createInitialAppInfo( + DexApplication.builder(new InternalOptions(new DexItemFactory(), new Reporter()), null) + .build()), + GraphLens.getIdentityLens(), NamingLens.getIdentityLens(), InitClassLens.getDefault(), Collections.emptyList(),
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java index 5cb94de..b567056 100644 --- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java +++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -27,6 +27,7 @@ import com.android.tools.r8.graph.DirectMappedDexApplication; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; +import com.android.tools.r8.graph.LazyLoadedDexApplication; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.naming.NamingLens; @@ -144,8 +145,9 @@ DexProgramClass sharedSynthesizedClass = makeClass(options, "SharedSynthesized", 100, Constants.MAX_NON_JUMBO_INDEX - 1, classes); - DexApplication.Builder builder = DirectMappedDexApplication.builder(options, Timing.empty()); - builder.addSynthesizedClass(sharedSynthesizedClass, false); + LazyLoadedDexApplication.Builder builder = + DirectMappedDexApplication.builder(options, Timing.empty()); + builder.addSynthesizedClass(sharedSynthesizedClass); classes.forEach(builder::addProgramClass); DexApplication application = builder.build(); @@ -153,9 +155,7 @@ options.programConsumer = consumer; ApplicationWriter writer = new ApplicationWriter( - application, AppView.createForD8(AppInfo.createInitialAppInfo(application)), - options, null, GraphLens.getIdentityLens(), InitClassLens.getDefault(),
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java index f503359..0ef3bdf 100644 --- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java +++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
@@ -369,7 +369,7 @@ // Ensure that the Class1 is actually in the correct split. Note that Class2 would have been // shaken away. - CodeInspector inspector = new CodeInspector(base, proguardMap.toString()); + CodeInspector inspector = new CodeInspector(base, proguardMap); ClassSubject subject = inspector.clazz("dexsplitsample.Class1"); assertTrue(subject.isPresent()); assertTrue(subject.isRenamed());
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java new file mode 100644 index 0000000..1ab86b3 --- /dev/null +++ b/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java
@@ -0,0 +1,77 @@ +// 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.enumunboxing; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.R8TestRunResult; +import com.android.tools.r8.TestParameters; +import java.util.List; +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 StringValueOfEnumUnboxingTest extends EnumUnboxingTestBase { + private final TestParameters parameters; + private final boolean enumValueOptimization; + private final EnumKeepRules enumKeepRules; + + @Parameters(name = "{0} valueOpt: {1} keep: {2}") + public static List<Object[]> data() { + return enumUnboxingTestParameters(); + } + + public StringValueOfEnumUnboxingTest( + TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) { + this.parameters = parameters; + this.enumValueOptimization = enumValueOptimization; + this.enumKeepRules = enumKeepRules; + } + + @Test + public void testEnumUnboxing() throws Exception { + Class<?> classToTest = Main.class; + R8TestRunResult run = + testForR8(parameters.getBackend()) + .addProgramClasses(classToTest, MyEnum.class) + .addKeepMainRule(classToTest) + .addKeepRules(enumKeepRules.getKeepRules()) + .enableNeverClassInliningAnnotations() + .enableInliningAnnotations() + .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) + .allowDiagnosticInfoMessages() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspectDiagnosticMessages( + m -> assertEnumIsUnboxed(MyEnum.class, classToTest.getSimpleName(), m)) + .run(parameters.getRuntime(), classToTest) + .assertSuccess(); + assertLines2By2Correct(run.getStdOut()); + } + + @NeverClassInline + enum MyEnum { + A, + B, + C + } + + static class Main { + public static void main(String[] args) { + System.out.println(MyEnum.A.ordinal()); + System.out.println(0); + System.out.println(getString(MyEnum.A)); + System.out.println("A"); + System.out.println(getString(null)); + System.out.println("null"); + } + + @NeverInline + private static String getString(MyEnum e) { + return String.valueOf(e); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java b/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java deleted file mode 100644 index 4094bb7..0000000 --- a/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. -package com.android.tools.r8.internal; - -import com.android.tools.r8.CompilationFailedException; -import com.android.tools.r8.CompilationMode; -import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import org.junit.Test; - -public class D8PhotosVerificationTest extends CompilationTestBase { - public static final String PHOTOS = - "third_party/photos/2017-06-06/PhotosEnglishOnlyLegacy_proguard.jar"; - - public void runD8AndCheckVerification(CompilationMode mode, String version) - throws ExecutionException, IOException, CompilationFailedException { - runAndCheckVerification(CompilerUnderTest.D8, mode, version, null, version); - } - - @Test - public void verify() throws Exception { - runD8AndCheckVerification(CompilationMode.RELEASE, PHOTOS); - } -}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java index 97b4db0..bbddb47 100644 --- a/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java +++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
@@ -69,8 +69,7 @@ new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original); ProtoApplicationStats baseline = new ProtoApplicationStats( - dexItemFactory, - new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString())); + dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap())); System.out.println(actual.getStats(baseline)); }
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java index b2498b5..0a304b1 100644 --- a/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java +++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java
@@ -78,8 +78,7 @@ new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original); ProtoApplicationStats baseline = new ProtoApplicationStats( - dexItemFactory, - new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString())); + dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap())); System.out.println(actual.getStats(baseline)); }
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java index b48bec3..79e7eb1 100644 --- a/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java +++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java
@@ -78,8 +78,7 @@ new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original); ProtoApplicationStats baseline = new ProtoApplicationStats( - dexItemFactory, - new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString())); + dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap())); System.out.println(actual.getStats(baseline)); }
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java index 632210e..09293ac 100644 --- a/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java +++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java
@@ -78,8 +78,7 @@ new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original); ProtoApplicationStats baseline = new ProtoApplicationStats( - dexItemFactory, - new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString())); + dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap())); System.out.println(actual.getStats(baseline)); }
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java index b351ca2..1d7686c 100644 --- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java +++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -14,7 +14,7 @@ import com.android.tools.r8.ir.code.InstructionListIterator; import com.android.tools.r8.ir.code.NumberGenerator; import com.android.tools.r8.ir.conversion.IRConverter; -import com.android.tools.r8.shaking.MainDexClasses; +import com.android.tools.r8.shaking.MainDexTracingResult; import com.android.tools.r8.smali.SmaliBuilder; import com.android.tools.r8.smali.SmaliBuilder.MethodSignature; import com.android.tools.r8.smali.SmaliTestBase; @@ -113,7 +113,7 @@ public String run() throws IOException { Timing timing = Timing.empty(); - IRConverter converter = new IRConverter(appView, timing, null, MainDexClasses.NONE); + IRConverter converter = new IRConverter(appView, timing, null, MainDexTracingResult.NONE); converter.replaceCodeForTesting(method, code); AndroidApp app = writeDex(); return runOnArtRaw(app, DEFAULT_MAIN_CLASS_NAME).stdout;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java new file mode 100644 index 0000000..5d13f66 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java
@@ -0,0 +1,181 @@ +// 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.typechecks; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assume.assumeTrue; + +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 com.google.common.collect.ImmutableList; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class InstanceOfMethodSpecializationTest extends TestBase { + + private static final List<String> EXPECTED = + ImmutableList.of( + "true", "false", "false", "true", "false", "true", "true", "false", "false", "true", + "true", "false", "true", "false", "true"); + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public InstanceOfMethodSpecializationTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addTestClasspath() + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines(EXPECTED); + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(InstanceOfMethodSpecializationTest.class) + .addKeepMainRule(TestClass.class) + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect(this::inspect) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines(EXPECTED); + } + + private void inspect(CodeInspector inspector) { + ClassSubject aClassSubject = inspector.clazz(A.class); + assertThat(aClassSubject, isPresent()); + assertThat(aClassSubject.uniqueMethodWithName("isA"), not(isPresent())); + assertThat(aClassSubject.uniqueMethodWithName("isB"), not(isPresent())); + assertThat(aClassSubject.uniqueMethodWithName("isC"), not(isPresent())); + assertThat(aClassSubject.uniqueMethodWithName("isSuper"), isPresent()); + assertThat(aClassSubject.uniqueMethodWithName("isSub"), isPresent()); + + ClassSubject bClassSubject = inspector.clazz(B.class); + assertThat(bClassSubject, isPresent()); + assertThat(bClassSubject.uniqueMethodWithName("isA"), not(isPresent())); + assertThat(bClassSubject.uniqueMethodWithName("isB"), not(isPresent())); + assertThat(bClassSubject.uniqueMethodWithName("isC"), not(isPresent())); + assertThat(bClassSubject.uniqueMethodWithName("isSuper"), not(isPresent())); + assertThat(bClassSubject.uniqueMethodWithName("isSub"), not(isPresent())); + + ClassSubject cClassSubject = inspector.clazz(C.class); + assertThat(cClassSubject, isPresent()); + assertThat(cClassSubject.uniqueMethodWithName("isA"), not(isPresent())); + assertThat(cClassSubject.uniqueMethodWithName("isB"), not(isPresent())); + assertThat(cClassSubject.uniqueMethodWithName("isC"), not(isPresent())); + assertThat(cClassSubject.uniqueMethodWithName("isSuper"), isPresent()); + assertThat(cClassSubject.uniqueMethodWithName("isSub"), isPresent()); + } + + public static class TestClass { + + public static void main(String[] args) { + A a = System.currentTimeMillis() > 0 ? new A() : new B(); + A b = System.currentTimeMillis() > 0 ? new B() : new A(); + A c = System.currentTimeMillis() > 0 ? new C() : new A(); + System.out.println(a.isA()); + System.out.println(a.isB()); + System.out.println(a.isC()); + System.out.println(a.isSuper()); + System.out.println(a.isSub()); + System.out.println(b.isA()); + System.out.println(b.isB()); + System.out.println(b.isC()); + System.out.println(b.isSuper()); + System.out.println(b.isSub()); + System.out.println(c.isA()); + System.out.println(c.isB()); + System.out.println(c.isC()); + System.out.println(c.isSuper()); + System.out.println(c.isSub()); + } + } + + public static class A { + + boolean isA() { + return true; + } + + boolean isB() { + return false; + } + + boolean isC() { + return false; + } + + boolean isSuper() { + return true; + } + + boolean isSub() { + return false; + } + } + + public static class B extends A { + + @Override + boolean isA() { + return true; + } + + @Override + boolean isB() { + return true; + } + + @Override + boolean isSuper() { + return false; + } + + @Override + boolean isSub() { + return true; + } + } + + public static class C extends A { + + @Override + boolean isA() { + return true; + } + + @Override + boolean isC() { + return true; + } + + @Override + boolean isSuper() { + return false; + } + + @Override + boolean isSub() { + return true; + } + } +}
diff --git a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java index 08a4ae9..0d96a65 100644 --- a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java +++ b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
@@ -162,10 +162,10 @@ annotationElement[0].value.asDexValueString().value.toSourceString()); } - private String getGeneratedProguardMap() throws IOException { + private Path getGeneratedProguardMap() throws IOException { Path mapFile = Paths.get(tmpOutputDir.getRoot().getCanonicalPath(), DEFAULT_MAP_FILENAME); if (Files.exists(mapFile)) { - return mapFile.toAbsolutePath().toString(); + return mapFile.toAbsolutePath(); } return null; }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java index fdc2ab9..37d2899 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -71,7 +71,7 @@ import com.android.tools.r8.utils.FileUtils; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.ListUtils; -import com.android.tools.r8.utils.MainDexList; +import com.android.tools.r8.utils.MainDexListParser; import com.android.tools.r8.utils.Reporter; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.ThreadUtils; @@ -182,7 +182,7 @@ } private static Set<DexType> parse(Path path, DexItemFactory itemFactory) throws IOException { - return MainDexList.parseList(StringResource.fromFile(path), itemFactory); + return MainDexListParser.parseList(StringResource.fromFile(path), itemFactory); } @Rule @@ -331,9 +331,11 @@ @Test public void singleEntryNoNewLine() throws Exception { DexItemFactory factory = new DexItemFactory(); - Set<DexType> types = MainDexList.parseList( - StringResource.fromString("desugaringwithmissingclasstest1/Main.class", Origin.unknown()), - factory); + Set<DexType> types = + MainDexListParser.parseList( + StringResource.fromString( + "desugaringwithmissingclasstest1/Main.class", Origin.unknown()), + factory); assertEquals(1, types.size()); assertEquals( "Ldesugaringwithmissingclasstest1/Main;", @@ -350,7 +352,7 @@ for (String entry : lines) { DexType type = factory.createType("L" + entry.replace(".class", "") + ";"); assertTrue(types.contains(type)); - assertSame(type, MainDexList.parseEntry(entry, factory)); + assertSame(type, MainDexListParser.parseEntry(entry, factory)); } } @@ -866,9 +868,7 @@ DirectMappedDexApplication application = builder.build().toDirect(); ApplicationWriter writer = new ApplicationWriter( - application, AppView.createForD8(AppInfo.createInitialAppInfo(application)), - options, null, GraphLens.getIdentityLens(), InitClassLens.getDefault(),
diff --git a/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java b/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java index bf33b1c..4f5e54a 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java
@@ -10,17 +10,39 @@ import com.android.tools.r8.ForceInline; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.google.common.collect.ImmutableList; import java.util.List; import org.hamcrest.CoreMatchers; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class MainDexWarningsTest extends TestBase { - private List<Class<?>> testClasses = ImmutableList.of(Main.class, Static.class, Static2.class); - private Class<?> mainClass = Main.class; + private static final List<Class<?>> testClasses = + ImmutableList.of(Main.class, Static.class, Static2.class); + private static final List<Class<?>> testClassesWithoutStatic = + ImmutableList.of(Main.class, Static2.class); + private static final Class<?> mainClass = Main.class; + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters() + .withDexRuntimes() + .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport()) + .build(); + } + + public MainDexWarningsTest(TestParameters parameters) { + this.parameters = parameters; + } private void classStaticGone(CodeInspector inspector) { assertThat(inspector.clazz(Static.class), CoreMatchers.not(isPresent())); @@ -29,12 +51,13 @@ @Test public void testNoWarningFromMainDexRules() throws Exception { - testForR8(Backend.DEX) + testForR8(parameters.getBackend()) .setMinApi(AndroidApiLevel.K) .addProgramClasses(testClasses) .addKeepMainRule(mainClass) // Include main dex rule for class Static. .addMainDexClassRules(Main.class, Static.class) + .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::classStaticGone) .assertNoMessages(); @@ -42,13 +65,14 @@ @Test public void testWarningFromManualMainDexList() throws Exception { - testForR8(Backend.DEX) + testForR8(parameters.getBackend()) .setMinApi(AndroidApiLevel.K) - .addProgramClasses(testClasses) + .addProgramClasses(testClassesWithoutStatic) .addKeepMainRule(mainClass) // Include explicit main dex entry for class Static. .addMainDexListClasses(Static.class) .allowDiagnosticWarningMessages() + .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::classStaticGone) .assertOnlyWarnings() @@ -59,15 +83,16 @@ @Test public void testWarningFromManualMainDexListWithRuleAsWell() throws Exception { - testForR8(Backend.DEX) + testForR8(parameters.getBackend()) .setMinApi(AndroidApiLevel.K) - .addProgramClasses(testClasses) + .addProgramClasses(testClassesWithoutStatic) .addKeepMainRule(mainClass) // Include explicit main dex entry for class Static. .addMainDexListClasses(Main.class, Static.class) // Include main dex rule for class Static2. .addMainDexClassRules(Static2.class) .allowDiagnosticWarningMessages() + .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::classStaticGone) .assertOnlyWarnings()
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java index 0c4f597..0da2866 100644 --- a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java +++ b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
@@ -33,11 +33,21 @@ private Builder() {} + public Builder add(StackTrace stackTrace) { + stackTraceLines.addAll(stackTrace.getStackTraceLines()); + return this; + } + public Builder add(StackTraceLine line) { stackTraceLines.add(line); return this; } + public Builder add(int i, StackTraceLine line) { + stackTraceLines.add(i, line); + return this; + } + public Builder addWithoutFileNameAndLineNumber(Class<?> clazz, String methodName) { return addWithoutFileNameAndLineNumber(clazz.getTypeName(), methodName); }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java index 47157aa..1639c79 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
@@ -47,7 +47,6 @@ @Test public void testR8() throws Exception { - assumeTrue(parameters.isCfRuntime()); testForR8(parameters.getBackend()) .addInnerClasses(RepackageAfterCollisionWithPackagePrivateSignatureTest.class) .addKeepClassAndMembersRules(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java index 69a88d0..c656981 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -109,7 +109,6 @@ @Test public void testR8() throws Exception { - assumeTrue(!enableExperimentalRepackaging || parameters.isCfRuntime()); testForR8(parameters.getBackend()) .addProgramFiles(ToolHelper.getClassFilesForTestPackage(TestClass.class.getPackage())) .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java new file mode 100644 index 0000000..00dd079 --- /dev/null +++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java
@@ -0,0 +1,104 @@ +// 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.repackage; + +import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY; +import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertFalse; + +import com.android.tools.r8.OutputMode; +import com.android.tools.r8.R8TestCompileResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.google.common.collect.ImmutableList; +import java.nio.file.Path; +import java.util.List; +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 RepackageWithMainDexListTest extends TestBase { + + private static final String REPACKAGE_DIR = "foo"; + + private final String flattenPackageHierarchyOrRepackageClasses; + private final TestParameters parameters; + + @Parameters(name = "{1}, kind: {0}") + public static List<Object[]> data() { + return buildParameters( + ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES), + getTestParameters() + .withDexRuntimes() + .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport()) + .build()); + } + + public RepackageWithMainDexListTest( + String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) { + this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses; + this.parameters = parameters; + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + // -keep,allowobfuscation does not prohibit repackaging. + .addKeepClassRulesWithAllowObfuscation(TestClass.class, OtherTestClass.class) + .addKeepRules( + "-keepclassmembers class " + TestClass.class.getTypeName() + " { <methods>; }") + .addKeepRules( + "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_DIR + "\"") + // Add a class that will be repackaged to the main dex list. + .addMainDexListClasses(TestClass.class) + .addOptionsModification( + options -> { + assertFalse(options.testing.enableExperimentalRepackaging); + options.testing.enableExperimentalRepackaging = true; + }) + // Debug mode to enable minimal main dex. + .debug() + .setMinApi(parameters.getApiLevel()) + .compile() + .apply(this::checkCompileResult) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("Hello world!"); + } + + private void checkCompileResult(R8TestCompileResult compileResult) throws Exception { + Path out = temp.newFolder().toPath(); + compileResult.app.writeToDirectory(out, OutputMode.DexIndexed); + Path classes = out.resolve("classes.dex"); + Path classes2 = out.resolve("classes2.dex"); + inspectMainDex(new CodeInspector(classes, compileResult.getProguardMap())); + inspectSecondaryDex(new CodeInspector(classes2, compileResult.getProguardMap())); + } + + private void inspectMainDex(CodeInspector inspector) { + assertThat(inspector.clazz(TestClass.class), isPresent()); + assertThat(inspector.clazz(OtherTestClass.class), not(isPresent())); + } + + private void inspectSecondaryDex(CodeInspector inspector) { + assertThat(inspector.clazz(TestClass.class), not(isPresent())); + assertThat(inspector.clazz(OtherTestClass.class), isPresent()); + } + + static class TestClass { + + public static void main(String[] args) { + System.out.println("Hello world!"); + } + } + + static class OtherTestClass {} +}
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java index 8365345..6f7c644 100644 --- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java +++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -220,12 +220,7 @@ Assert.assertEquals(resultInput.toString(), resultOutput.toString()); } if (inspection != null) { - CodeInspector inspector = - new CodeInspector( - out, - minify.isMinify() - ? proguardMap.toString() - : null); + CodeInspector inspector = new CodeInspector(out, minify.isMinify() ? proguardMap : null); inspection.accept(inspector); } return; @@ -252,9 +247,7 @@ if (dexComparator != null) { CodeInspector ref = new CodeInspector(Paths.get(originalDex)); - CodeInspector inspector = new CodeInspector(out, - minify.isMinify() ? proguardMap.toString() - : null); + CodeInspector inspector = new CodeInspector(out, minify.isMinify() ? proguardMap : null); dexComparator.accept(ref, inspector); } } else { @@ -265,8 +258,7 @@ } if (inspection != null) { - CodeInspector inspector = - new CodeInspector(out, minify.isMinify() ? proguardMap.toString() : null); + CodeInspector inspector = new CodeInspector(out, minify.isMinify() ? proguardMap : null); inspection.accept(inspector); } }
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java index ac64695..693af00 100644 --- a/src/test/java/com/android/tools/r8/utils/Smali.java +++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -115,9 +115,7 @@ DexApplication dexApp = new ApplicationReader(app, options, Timing.empty()).read(executor); ApplicationWriter writer = new ApplicationWriter( - dexApp, AppView.createForD8(AppInfo.createInitialAppInfo(dexApp)), - options, null, GraphLens.getIdentityLens(), InitClassLens.getDefault(),
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java index 3125afe..04a8671 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -36,6 +36,11 @@ } @Override + public MethodSubject uniqueInstanceInitializer() { + return new AbsentMethodSubject(); + } + + @Override public MethodSubject uniqueMethodWithName(String name) { return new AbsentMethodSubject(); }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java index 28fd839..d3c1ecc 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -95,6 +95,8 @@ public abstract MethodSubject method(String returnType, String name, List<String> parameters); + public abstract MethodSubject uniqueInstanceInitializer(); + public abstract MethodSubject uniqueMethodWithName(String name); public MethodSubject mainMethod() {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java index 1428897..6a5b949 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -77,8 +77,13 @@ this(Paths.get(path)); } - public CodeInspector(Path file, String mappingFile) throws IOException { - this(Collections.singletonList(file), mappingFile, null); + public CodeInspector(Path file, String proguardMapContent) throws IOException { + this(AndroidApp.builder().addProgramFile(file).build(), proguardMapContent); + } + + public CodeInspector(Path file, Path mappingFile) throws IOException { + this( + Collections.singletonList(file), mappingFile != null ? mappingFile.toString() : null, null); } public CodeInspector(Path file) throws IOException { @@ -111,9 +116,7 @@ } public CodeInspector(AndroidApp app) throws IOException { - this( - new ApplicationReader(app, runOptionsConsumer(null), Timing.empty()) - .read(app.getProguardMapOutputData())); + this(app, (Consumer<InternalOptions>) null); } public CodeInspector(AndroidApp app, Consumer<InternalOptions> optionsConsumer) @@ -144,7 +147,8 @@ public CodeInspector(AndroidApp app, String proguardMapContent) throws IOException { this( new ApplicationReader(app, runOptionsConsumer(null), Timing.empty()) - .read(StringResource.fromString(proguardMapContent, Origin.unknown()))); + .read( + StringResource.fromString(proguardMapContent, Origin.unknown()))); } public CodeInspector(DexApplication application) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java index 957e78a..d4cd896 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.utils.codeinspector; import com.android.tools.r8.graph.DexEncodedField; +import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexValue; public abstract class FieldSubject extends MemberSubject { @@ -13,6 +14,10 @@ public abstract DexEncodedField getField(); + public DexField getFieldReference() { + return getField().field; + } + public abstract DexValue getStaticValue(); public abstract boolean isRenamed();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java index f12840f..8d925da 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -119,6 +119,16 @@ } @Override + public MethodSubject uniqueInstanceInitializer() { + MethodSubject methodSubject = null; + for (FoundMethodSubject candidate : allMethods(FoundMethodSubject::isInstanceInitializer)) { + assert methodSubject == null; + methodSubject = candidate; + } + return methodSubject != null ? methodSubject : new AbsentMethodSubject(); + } + + @Override public MethodSubject uniqueMethodWithName(String name) { MethodSubject methodSubject = null; for (FoundMethodSubject candidate : allMethods()) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java index 5842c9b..f2b7fe3 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AccessFlags; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexField; import com.android.tools.r8.naming.retrace.StackTrace; import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine; import com.android.tools.r8.references.MethodReference; @@ -558,6 +559,44 @@ }; } + public static Matcher<MethodSubject> writesInstanceField(DexField field) { + return new TypeSafeMatcher<MethodSubject>() { + @Override + protected boolean matchesSafely(MethodSubject methodSubject) { + return methodSubject + .streamInstructions() + .filter(InstructionSubject::isInstancePut) + .map(InstructionSubject::getField) + .anyMatch(field::equals); + } + + @Override + public void describeTo(Description description) { + description.appendText( + "The field " + field.name.toSourceString() + " is not written by the method."); + } + }; + } + + public static Matcher<MethodSubject> readsInstanceField(DexField field) { + return new TypeSafeMatcher<MethodSubject>() { + @Override + protected boolean matchesSafely(MethodSubject methodSubject) { + return methodSubject + .streamInstructions() + .filter(InstructionSubject::isInstanceGet) + .map(InstructionSubject::getField) + .anyMatch(field::equals); + } + + @Override + public void describeTo(Description description) { + description.appendText( + "The field " + field.name.toSourceString() + " is not read by the method."); + } + }; + } + public static class LinePosition { private final MethodReference methodReference; private final int minifiedPosition;
diff --git a/third_party/photos/2017-06-06.tar.gz.sha1 b/third_party/photos/2017-06-06.tar.gz.sha1 deleted file mode 100644 index b21e5a6..0000000 --- a/third_party/photos/2017-06-06.tar.gz.sha1 +++ /dev/null
@@ -1 +0,0 @@ -80389d76881463daf28b47f402c5013f499966bf \ No newline at end of file