Merge commit '8a8c4b56794f822e0dd053f6e510b8b6635234ab' into dev-release
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java index 2e73927..99ff6a7 100644 --- a/src/main/java/com/android/tools/r8/D8.java +++ b/src/main/java/com/android/tools/r8/D8.java
@@ -341,7 +341,7 @@ new KotlinMetadataRewriter(appView, prefixRewritingNamingLens).runForD8(executor); new ApplicationWriter( cfApp, - null, + appView, options, null, GraphLens.getIdentityLens(),
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java index 7203f8e..9935d84 100644 --- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java +++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -100,7 +100,7 @@ try { new ApplicationWriter( appView.appInfo().app(), - null, + appView, options, markers, GraphLens.getIdentityLens(),
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java index aae1486..ef71e03 100644 --- a/src/main/java/com/android/tools/r8/L8.java +++ b/src/main/java/com/android/tools/r8/L8.java
@@ -99,8 +99,12 @@ }); assert !options.cfToCfDesugar; if (shrink) { - R8.run(r8Command); - } else { + AndroidApp r8CommandInputApp = r8Command.getInputApp(); + InternalOptions r8CommandInternalOptions = r8Command.getInternalOptions(); + // TODO(b/167843161): Disable temporarily enum unboxing in L8 due to naming issues. + r8CommandInternalOptions.enableEnumUnboxing = false; + R8.runForTesting(r8CommandInputApp, r8CommandInternalOptions); + } else if (d8Command != null) { D8.run(d8Command, executorService); } } finally {
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java index a2cf589..db24f23 100644 --- a/src/main/java/com/android/tools/r8/L8Command.java +++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -260,9 +260,6 @@ if (!hasDesugaredLibraryConfiguration()) { reporter.error("L8 requires a desugared library configuration"); } - if (getProgramConsumer() instanceof ClassFileConsumer) { - reporter.error("L8 does not support compiling to class files"); - } if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) { reporter.error("L8 does not support compiling to dex per class"); } @@ -271,6 +268,9 @@ } else if (getMainDexListConsumer() != null) { reporter.error("L8 does not support generating a main dex list"); } + if (isShrinking() && getProgramConsumer() instanceof ClassFileConsumer) { + reporter.error("L8 does not support shrinking when generating class files"); + } super.validate(); } @@ -292,12 +292,12 @@ D8Command d8Command = null; AndroidApp inputs = getAppBuilder().build(); - DesugaredLibrary desugaredLibrary = new DesugaredLibrary(); - + ProgramConsumer l8CfConsumer = null; if (isShrinking()) { + l8CfConsumer = new InMemoryJarContent(); R8Command.Builder r8Builder = new CompatProguardCommandBuilder(true, getReporter()) - .addProgramResourceProvider(desugaredLibrary) + .addProgramResourceProvider((ProgramResourceProvider) l8CfConsumer) .setSynthesizedClassesPrefix( libraryConfiguration.getSynthesizedLibraryClassesPackagePrefix()) .setMinApiLevel(getMinApiLevel()) @@ -316,10 +316,11 @@ libraryConfiguration.getExtraKeepRules(), Origin.unknown()); r8Builder.addProguardConfigurationFiles(proguardConfigFiles); r8Command = r8Builder.makeCommand(); - } else { + } else if (!(getProgramConsumer() instanceof ClassFileConsumer)) { + l8CfConsumer = new InMemoryJarContent(); D8Command.Builder d8Builder = D8Command.builder(getReporter()) - .addProgramResourceProvider(desugaredLibrary) + .addProgramResourceProvider((ProgramResourceProvider) l8CfConsumer) .setSynthesizedClassesPrefix( libraryConfiguration.getSynthesizedLibraryClassesPackagePrefix()) .setMinApiLevel(getMinApiLevel()) @@ -332,13 +333,17 @@ d8Builder.addLibraryResourceProvider(libraryResourceProvider); } d8Command = d8Builder.makeCommand(); + } else { + assert getProgramConsumer() instanceof ClassFileConsumer; + l8CfConsumer = getProgramConsumer(); + d8Command = null; } return new L8Command( r8Command, d8Command, inputs, getMode(), - desugaredLibrary, + l8CfConsumer, getMainDexListConsumer(), getMinApiLevel(), getReporter(), @@ -352,7 +357,7 @@ } } - static class DesugaredLibrary implements ClassFileConsumer, ProgramResourceProvider { + static class InMemoryJarContent implements ClassFileConsumer, ProgramResourceProvider { private final List<ProgramResource> resources = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java index e083cec..5d9392c 100644 --- a/src/main/java/com/android/tools/r8/L8CommandParser.java +++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -88,7 +88,7 @@ private L8Command.Builder parse(String[] args, Origin origin, L8Command.Builder builder) { CompilationMode compilationMode = null; Path outputPath = null; - OutputMode outputMode = null; + OutputMode outputMode = OutputMode.DexIndexed; boolean hasDefinedApiLevel = false; OrderedClassFileResourceProvider.Builder classpathBuilder = OrderedClassFileResourceProvider.builder(); @@ -149,6 +149,8 @@ builder.addProguardConfigurationFiles(Paths.get(nextArg)); } else if (arg.equals("--desugared-lib")) { builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg))); + } else if (arg.equals("--classfile")) { + outputMode = OutputMode.ClassFile; } else if (arg.equals(THREAD_COUNT_FLAG)) { parsePositiveIntArgument( builder::error, THREAD_COUNT_FLAG, nextArg, origin, builder::setThreadCount); @@ -167,9 +169,6 @@ if (compilationMode != null) { builder.setMode(compilationMode); } - if (outputMode == null) { - outputMode = OutputMode.DexIndexed; - } if (outputPath == null) { outputPath = Paths.get("."); }
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index 9d6b199..3a9b0d9 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -78,6 +78,7 @@ import com.android.tools.r8.optimize.VisibilityBridgeRemover; import com.android.tools.r8.origin.CommandLineOrigin; import com.android.tools.r8.repackaging.Repackaging; +import com.android.tools.r8.repackaging.RepackagingLens; import com.android.tools.r8.shaking.AbstractMethodRemover; import com.android.tools.r8.shaking.AnnotationRemover; import com.android.tools.r8.shaking.AppInfoWithLiveness; @@ -226,12 +227,7 @@ Set<Marker> markers = new HashSet<>(options.itemFactory.extractMarkers()); markers.remove(marker); if (options.isGeneratingClassFiles()) { - new CfApplicationWriter( - appView, - marker, - graphLens, - namingLens, - proguardMapSupplier) + new CfApplicationWriter(appView, marker, graphLens, namingLens, proguardMapSupplier) .write(options.getClassFileConsumer()); } else { new ApplicationWriter( @@ -390,7 +386,7 @@ assert appView.rootSet().verifyKeptFieldsAreAccessedAndLive(appViewWithLiveness.appInfo()); assert appView.rootSet().verifyKeptMethodsAreTargetedAndLive(appViewWithLiveness.appInfo()); assert appView.rootSet().verifyKeptTypesAreLive(appViewWithLiveness.appInfo()); - assert appView.rootSet().verifyKeptItemsAreKept(appView.appInfo().app(), appView.appInfo()); + assert appView.rootSet().verifyKeptItemsAreKept(appView); missingClasses = Sets.union(missingClasses, appViewWithLiveness.appInfo().getMissingTypes()); @@ -551,7 +547,8 @@ if (options.enableHorizontalClassMerging) { timing.begin("HorizontalClassMerger"); HorizontalClassMerger merger = - new HorizontalClassMerger(appViewWithLiveness, mainDexClasses); + new HorizontalClassMerger( + appViewWithLiveness, mainDexClasses, classMergingEnqueuerExtension); HorizontalClassMergerGraphLens lens = merger.run(); if (lens != null) { appView.setHorizontallyMergedClasses(lens.getHorizontallyMergedClasses()); @@ -809,7 +806,15 @@ // Perform repackaging. // TODO(b/165783399): Consider making repacking available without minification. if (options.isMinifying() && options.testing.enableExperimentalRepackaging) { - new Repackaging(appView.withLiveness()).run(executorService, timing); + DirectMappedDexApplication.Builder appBuilder = + appView.appInfo().app().asDirect().builder(); + // TODO(b/165783399): We need to deal with non-rebound member references in the writer, + // possibly by adding a member rebinding lens on top of the repackaging lens. + RepackagingLens lens = + new Repackaging(appView.withLiveness()).run(appBuilder, executorService, timing); + if (lens != null) { + appView.rewriteWithLensAndApplication(lens, appBuilder.build()); + } } // Perform minification. @@ -886,7 +891,7 @@ if (options.isShrinking() || options.isMinifying() || options.getProguardConfiguration().hasApplyMappingFile()) { - assert appView.rootSet().verifyKeptItemsAreKept(appView.appInfo().app(), appView.appInfo()); + assert appView.rootSet().verifyKeptItemsAreKept(appView); } assert appView .graphLens() @@ -912,6 +917,7 @@ .run(appView.appInfo().classes(), executorService); // Generate the resulting application resources. + // TODO(b/165783399): Apply the graph lens to all instructions in the CF and DEX backends. writeApplication( executorService, appView,
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java index 0affffd..8174420 100644 --- a/src/main/java/com/android/tools/r8/ResourceShrinker.java +++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -288,7 +288,8 @@ // of integers. This can be improved later, but for now we make sure no ints are missed. } - methodIntArrayPayloadOffsets.add(fillArrayData.getPayloadOffset() + fillArrayData.offset); + methodIntArrayPayloadOffsets.add( + fillArrayData.getPayloadOffset() + fillArrayData.getOffset()); } private void processAnnotationValue(DexValue value) {
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 0e86dc7..80dd656 100644 --- a/src/main/java/com/android/tools/r8/bisect/Bisect.java +++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -10,6 +10,8 @@ import com.android.tools.r8.dex.ApplicationReader; import com.android.tools.r8.dex.ApplicationWriter; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.graph.AppInfo; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.InitClassLens; @@ -188,7 +190,7 @@ ApplicationWriter writer = new ApplicationWriter( app, - null, + AppView.createForD8(AppInfo.createInitialAppInfo(app)), options, null, null,
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java index 21a5392..5fb9822 100644 --- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java +++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.cf; +import static com.android.tools.r8.utils.StringUtils.join; + import com.android.tools.r8.cf.code.CfArithmeticBinop; import com.android.tools.r8.cf.code.CfArrayLength; import com.android.tools.r8.cf.code.CfArrayLoad; @@ -18,6 +20,7 @@ import com.android.tools.r8.cf.code.CfDexItemBasedConstString; 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.CfGoto; import com.android.tools.r8.cf.code.CfIf; import com.android.tools.r8.cf.code.CfIfCmp; @@ -46,6 +49,7 @@ import com.android.tools.r8.cf.code.CfTryCatch; import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.graph.CfCode; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; @@ -185,6 +189,23 @@ return type("ImmutableList", ImmutableList.of("com", "google", "common", "collect")); } + private String int2ReferenceAVLTreeMapType() { + return type( + "Int2ReferenceAVLTreeMap", ImmutableList.of("it", "unimi", "dsi", "fastutil", "ints")); + } + + private String frameTypeType() { + return r8Type("FrameType", ImmutableList.of("cf", "code", "CfFrame")); + } + + private String dexItemFactoryType() { + return r8Type("DexItemFactory", "graph"); + } + + private String arraysType() { + return type("Arrays", ImmutableList.of("java", "util")); + } + private String r8Type(String name, String pkg) { return r8Type(name, Collections.singletonList(pkg)); } @@ -427,7 +448,40 @@ @Override public void print(CfFrame frame) { - throw new Unimplemented(frame.getClass().getSimpleName()); + String keys = join(frame.getLocals().keySet(), ",", BraceType.NONE); + String values = join(frame.getLocals().values(), ",", BraceType.NONE, this::frameTypeType); + String stack = join(frame.getStack(), ",", BraceType.NONE, this::frameTypeType); + printNewInstruction( + "CfFrame", + "new " + + int2ReferenceAVLTreeMapType() + + "<>(" + + "new int[] {" + + keys + + "}," + + "new " + + frameTypeType() + + "[] { " + + values + + " })", + arraysType() + ".asList(" + stack + ")"); + } + + private String frameTypeType(FrameType frameType) { + if (frameType.isTop()) { + return frameTypeType() + ".top()"; + } else if (frameType.isUninitializedThis()) { + return frameTypeType() + ".uninitializedThis()"; + } else if (frameType.isUninitializedNew()) { + return frameTypeType() + ".uninitializedNew(new " + cfType("CfLabel") + "())"; + } else { + assert frameType.isInitialized(); + if (frameType.getInitializedType() == DexItemFactory.nullValueType) { + return frameTypeType() + ".initialized(" + dexItemFactoryType() + ".nullValueType)"; + } else { + return frameTypeType() + ".initialized(" + dexType(frameType.getInitializedType()) + ")"; + } + } } @Override
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 6f4e958..b679a54 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -129,7 +130,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 1290256..6510e23 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -19,7 +20,8 @@ public class CfArrayLength extends CfInstruction { @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 02e20ea..a9d754e 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.MemberType; import com.android.tools.r8.ir.code.ValueType; @@ -56,7 +57,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 1976942..5e8c152 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.MemberType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -54,7 +55,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 a46e68c..7f6a380 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -32,8 +33,9 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { - visitor.visitTypeInsn(Opcodes.CHECKCAST, lens.lookupInternalName(type)); + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { + visitor.visitTypeInsn(Opcodes.CHECKCAST, lens.lookupInternalName(graphLens.lookupType(type))); } @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 8d128be..1163483 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.Cmp; import com.android.tools.r8.ir.code.Cmp.Bias; @@ -79,7 +80,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 05d8568..37255ff 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
@@ -8,6 +8,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -32,8 +33,12 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { - visitor.visitLdcInsn(Type.getObjectType(getInternalName(lens))); + public void write( + MethodVisitor visitor, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens) { + visitor.visitLdcInsn(Type.getObjectType(getInternalName(graphLens, namingLens))); } @Override @@ -46,11 +51,11 @@ return true; } - private String getInternalName(NamingLens lens) { + private String getInternalName(GraphLens graphLens, NamingLens namingLens) { switch (type.toShorty()) { case '[': case 'L': - return lens.lookupInternalName(type); + return namingLens.lookupInternalName(graphLens.lookupType(type)); case 'Z': return "java/lang/Boolean/TYPE"; case 'B':
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 89fae02..c5d52f2 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.graph.UseRegistry.MethodHandleUse; @@ -31,7 +32,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { visitor.visitLdcInsn(handle.toAsmHandle(lens)); }
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 8283278..17577b9 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -31,7 +32,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { visitor.visitLdcInsn(Type.getType(type.toDescriptorString(lens))); }
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 889a63c..1c5e970 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -19,7 +20,8 @@ public class CfConstNull extends CfInstruction { @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 54519864..b4e63a9 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -56,7 +57,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 3b113cb..649f756 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -42,7 +43,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 94eadd1..79e59db 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
@@ -8,6 +8,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -48,7 +49,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 7e31f5b..32c8494 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
@@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -53,10 +54,13 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { - String owner = lens.lookupInternalName(field.holder); - String name = lens.lookupName(declaringField).toString(); - String desc = lens.lookupDescriptor(field.type).toString(); + 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(); 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 f1058d6..152f9e9 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
@@ -10,6 +10,7 @@ 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -223,7 +224,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { int stackCount = computeStackCount(); Object[] stackTypes = computeStackTypes(stackCount, lens); int localsCount = computeLocalsCount();
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 bbb8996..d38c0fe 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -44,7 +45,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 a6d0fca..f64d79c 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.If; import com.android.tools.r8.ir.code.If.Type; @@ -69,7 +70,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 24c81a5..1ee17b1 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.If; import com.android.tools.r8.ir.code.If.Type; @@ -69,7 +70,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 4ce64a4..edba7b4 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.code.NumericType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -26,7 +27,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 115d27a..afcae7d 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
@@ -8,6 +8,7 @@ import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -37,7 +38,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + 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();
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 ca6b7ed..fc26a95 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -41,7 +42,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { visitor.visitTypeInsn(Opcodes.INSTANCEOF, lens.lookupInternalName(type)); } @@ -52,7 +54,7 @@ @Override void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) { - registry.registerTypeReference(type); + registry.registerInstanceOf(type); } @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 041409b..16ef22f 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.ClasspathMethod; import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.UseRegistry; @@ -20,7 +21,8 @@ public abstract class CfInstruction { - public abstract void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens); + public abstract void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens); 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 510249b..3851031 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
@@ -71,10 +71,12 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { - String owner = lens.lookupInternalName(method.holder); - String name = lens.lookupName(method).toString(); - String desc = method.proto.toDescriptorString(lens); + 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); }
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 fac04cd..f57046b 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
@@ -12,6 +12,7 @@ import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; 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.UseRegistry; import com.android.tools.r8.ir.code.ValueType; @@ -36,7 +37,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { DexMethodHandle bootstrapMethod = callSite.bootstrapMethod; List<DexValue> bootstrapArgs = callSite.bootstrapArgs; Object[] bsmArgs = new Object[bootstrapArgs.size()];
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 2fc78ea..88659de 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.CompilationError; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -29,7 +30,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 6cc49de..19ba74a 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -42,7 +43,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 0680d73..80bb1da 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -56,7 +57,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 f34a7d7..0f5bd4e 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -104,7 +105,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 7fd0167..ebefa78 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.code.Monitor.Type; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -30,7 +31,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 1f787f8..69a69af 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -37,7 +38,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { visitor.visitMultiANewArrayInsn(lens.lookupInternalName(type), dimensions); }
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 cd61c29..32ef906 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -31,7 +32,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 8bd1249..e0b8785 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -31,7 +32,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { visitor.visitTypeInsn(Opcodes.NEW, lens.lookupInternalName(type)); }
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 9ef5f1b..6c3869b 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
@@ -8,6 +8,7 @@ import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -66,7 +67,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { if (type.isPrimitiveArrayType()) { visitor.visitIntInsn(Opcodes.NEWARRAY, getPrimitiveTypeCode()); } else {
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 4578bff..18a2ae6 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -18,7 +19,8 @@ public class CfNop extends CfInstruction { @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 afbff92..405fb42 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.NumericType; import com.android.tools.r8.ir.code.ValueType; @@ -41,7 +42,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 93febbb..70a3f07 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.code.Position; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -26,7 +27,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 5934617..d66d6cf 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -53,7 +54,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 c9d7f51..83b5e60 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -23,7 +24,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 ef291d0..a4ecce6 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
@@ -7,6 +7,7 @@ import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unreachable; 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.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -75,7 +76,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 d8f13d1..c3ce5db 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
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.CfPrinter; import com.android.tools.r8.errors.Unreachable; 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.ir.code.ValueType; import com.android.tools.r8.ir.conversion.CfSourceCode; @@ -56,7 +57,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 3169da0..3a3c72e 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -69,7 +70,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 9b88cb5..3b49cb0 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
@@ -5,6 +5,7 @@ import com.android.tools.r8.cf.CfPrinter; 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.ir.conversion.CfSourceCode; import com.android.tools.r8.ir.conversion.CfState; @@ -24,7 +25,8 @@ } @Override - public void write(MethodVisitor visitor, InitClassLens initClassLens, NamingLens lens) { + public void write( + MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) { 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 f472800..569b358 100644 --- a/src/main/java/com/android/tools/r8/code/CheckCast.java +++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -3,12 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class CheckCast extends Format21c { +public class CheckCast extends Format21c<DexType> { public static final int OPCODE = 0x1f; public static final String NAME = "CheckCast"; @@ -38,6 +39,11 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); + } + + @Override public CheckCast asCheckCast() { return this; } @@ -53,7 +59,7 @@ } public DexType getType() { - return (DexType) BBBB; + return BBBB; } @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 33cef07..2f8f7db 100644 --- a/src/main/java/com/android/tools/r8/code/ConstClass.java +++ b/src/main/java/com/android/tools/r8/code/ConstClass.java
@@ -3,12 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class ConstClass extends Format21c { +public class ConstClass extends Format21c<DexType> { public static final int OPCODE = 0x1c; public static final String NAME = "ConstClass"; @@ -38,12 +39,17 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); + } + + @Override public void registerUse(UseRegistry registry) { registry.registerConstClass(getType()); } public DexType getType() { - return (DexType) BBBB; + return BBBB; } @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 fd17fef..8518946 100644 --- a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java +++ b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +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.ObjectToOffsetMapping; @@ -13,7 +14,7 @@ import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; -public class ConstMethodHandle extends Format21c { +public class ConstMethodHandle extends Format21c<DexMethodHandle> { public static final int OPCODE = 0xfe; public static final String NAME = "ConstMethodHandle"; @@ -28,7 +29,7 @@ } public DexMethodHandle getMethodHandle() { - return (DexMethodHandle) BBBB; + return BBBB; } @Override @@ -72,8 +73,13 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getMethodHandle().collectIndexedItems(indexedItems); + } + + @Override public void buildIR(IRBuilder builder) { - builder.addConstMethodHandle(AA, (DexMethodHandle) BBBB); + builder.addConstMethodHandle(AA, BBBB); } @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 84c090a..8eb5443 100644 --- a/src/main/java/com/android/tools/r8/code/ConstMethodType.java +++ b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +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.ObjectToOffsetMapping; @@ -12,7 +13,7 @@ import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; -public class ConstMethodType extends Format21c { +public class ConstMethodType extends Format21c<DexProto> { public static final int OPCODE = 0xff; public static final String NAME = "ConstMethodType"; @@ -27,7 +28,7 @@ } public DexProto getMethodType() { - return (DexProto) BBBB; + return BBBB; } @Override @@ -70,8 +71,13 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getMethodType().collectIndexedItems(indexedItems); + } + + @Override public void buildIR(IRBuilder builder) { - builder.addConstMethodType(AA, (DexProto) BBBB); + builder.addConstMethodType(AA, BBBB); } @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 a5733ad..261016b 100644 --- a/src/main/java/com/android/tools/r8/code/ConstString.java +++ b/src/main/java/com/android/tools/r8/code/ConstString.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +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.ObjectToOffsetMapping; @@ -11,7 +12,7 @@ import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; -public class ConstString extends Format21c { +public class ConstString extends Format21c<DexString> { public static final int OPCODE = 0x1a; public static final String NAME = "ConstString"; @@ -26,7 +27,12 @@ } public DexString getString() { - return (DexString) BBBB; + return BBBB; + } + + @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getString().collectIndexedItems(indexedItems); } @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 9df8285..20f2047 100644 --- a/src/main/java/com/android/tools/r8/code/DexInitClass.java +++ b/src/main/java/com/android/tools/r8/code/DexInitClass.java
@@ -7,7 +7,6 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexField; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.graph.UseRegistry; @@ -37,10 +36,9 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { DexField field = indexedItems.getInitClassLens().getInitClassField(clazz); - field.collectIndexedItems(indexedItems, method, instructionOffset); + field.collectIndexedItems(indexedItems); } @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 5ae471a..1fb6e8c 100644 --- a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java +++ b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +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.ObjectToOffsetMapping; @@ -12,7 +13,7 @@ import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo; import java.nio.ShortBuffer; -public class DexItemBasedConstString extends Format21c { +public class DexItemBasedConstString extends Format21c<DexReference> { public static final String NAME = "DexItemBasedConstString"; public static final String SMALI_NAME = "const-string*"; @@ -26,7 +27,7 @@ } public DexReference getItem() { - return (DexReference) BBBB; + return BBBB; } public NameComputationInfo<?> getNameComputationInfo() { @@ -34,6 +35,11 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getItem().collectIndexedItems(indexedItems); + } + + @Override public String getName() { return NAME; }
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 4f2ebb6..1932e16 100644 --- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java +++ b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
@@ -3,11 +3,12 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.ir.conversion.IRBuilder; -public class FilledNewArray extends Format35c { +public class FilledNewArray extends Format35c<DexType> { public static final int OPCODE = 0x24; public static final String NAME = "FilledNewArray"; @@ -36,8 +37,13 @@ return OPCODE; } + @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); + } + public DexType getType() { - return (DexType) BBBB; + return BBBB; } @Override
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 0ee63b0..7fc2adc 100644 --- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java +++ b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
@@ -3,11 +3,12 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.ir.conversion.IRBuilder; -public class FilledNewArrayRange extends Format3rc { +public class FilledNewArrayRange extends Format3rc<DexType> { public static final int OPCODE = 0x25; public static final String NAME = "FilledNewArrayRange"; @@ -36,8 +37,13 @@ return OPCODE; } + @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); + } + public DexType getType() { - return (DexType) BBBB; + return BBBB; } @Override
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 8365a28..4c61fa3 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,6 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -54,8 +53,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 0b497fb..8eed571 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,6 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -46,8 +45,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 4d9a01b..f2b8ac2 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -59,8 +58,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 dd5a76b..318bf04 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -54,8 +53,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 07ec8e2..ac90623 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -58,8 +57,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 ee32757..f145476 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,6 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -54,8 +53,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 faa9d58..04848f0 100644 --- a/src/main/java/com/android/tools/r8/code/Format21c.java +++ b/src/main/java/com/android/tools/r8/code/Format21c.java
@@ -4,27 +4,25 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; 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; -abstract class Format21c extends Base2Format { +abstract class Format21c<T extends IndexedDexItem> extends Base2Format { public final short AA; - public IndexedDexItem BBBB; + public T BBBB; // AA | op | [type|field|string]@BBBB - Format21c(int high, BytecodeStream stream, IndexedDexItem[] map) { + Format21c(int high, BytecodeStream stream, T[] map) { super(stream); AA = (short) high; BBBB = map[read16BitValue(stream)]; } - protected Format21c(int AA, IndexedDexItem BBBB) { + protected Format21c(int AA, T BBBB) { assert 0 <= AA && AA <= Constants.U8BIT_MAX; this.AA = (short) AA; this.BBBB = BBBB; @@ -46,7 +44,7 @@ if (other == null || this.getClass() != other.getClass()) { return false; } - Format21c o = (Format21c) other; + Format21c<?> o = (Format21c<?>) other; return o.AA == AA && o.BBBB.equals(BBBB); } @@ -63,17 +61,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - BBBB.collectIndexedItems(indexedItems, method, instructionOffset); - } - - @Override public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) { if (other == null || this.getClass() != other.getClass()) { return false; } - Format21c o = (Format21c) other; + Format21c<?> o = (Format21c<?>) other; return o.AA == AA && equality.test(BBBB, o.BBBB); } }
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 074a0a0..221dc9e 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import java.nio.ShortBuffer; @@ -49,8 +48,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 48f457c..a9d7dc1 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; @@ -61,8 +60,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 7266a6a..d89b029 100644 --- a/src/main/java/com/android/tools/r8/code/Format21t.java +++ b/src/main/java/com/android/tools/r8/code/Format21t.java
@@ -5,7 +5,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.ir.code.If.Type; import com.android.tools.r8.ir.code.ValueTypeConstraint; @@ -79,8 +78,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 86a51b6..3952eb7 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; @@ -66,8 +65,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 16082a4..751ef61 100644 --- a/src/main/java/com/android/tools/r8/code/Format22c.java +++ b/src/main/java/com/android/tools/r8/code/Format22c.java
@@ -4,29 +4,27 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; 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 extends Base2Format { +public abstract class Format22c<T extends IndexedDexItem> extends Base2Format { public final byte A; public final byte B; - public IndexedDexItem CCCC; + public T CCCC; // vB | vA | op | [type|field]@CCCC - /*package*/ Format22c(int high, BytecodeStream stream, IndexedDexItem[] map) { + /*package*/ Format22c(int high, BytecodeStream stream, T[] map) { super(stream); A = (byte) (high & 0xf); B = (byte) ((high >> 4) & 0xf); CCCC = map[read16BitValue(stream)]; } - /*package*/ Format22c(int A, int B, IndexedDexItem CCCC) { + /*package*/ Format22c(int A, int B, T CCCC) { assert 0 <= A && A <= Constants.U4BIT_MAX; assert 0 <= B && B <= Constants.U4BIT_MAX; this.A = (byte) A; @@ -50,7 +48,7 @@ if (other == null || this.getClass() != other.getClass()) { return false; } - Format22c o = (Format22c) other; + Format22c<?> o = (Format22c<?>) other; return o.A == A && o.B == B && o.CCCC.equals(CCCC); } @@ -67,17 +65,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - CCCC.collectIndexedItems(indexedItems, method, instructionOffset); - } - - @Override public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) { if (other == null || this.getClass() != other.getClass()) { return false; } - Format22c o = (Format22c) other; + Format22c<?> o = (Format22c<?>) other; return o.A == A && o.B == B && equality.test(CCCC, o.CCCC); } }
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 9666b21..25c51d6 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.utils.StringUtils; @@ -66,8 +65,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 66e5df1..6505e5c 100644 --- a/src/main/java/com/android/tools/r8/code/Format22t.java +++ b/src/main/java/com/android/tools/r8/code/Format22t.java
@@ -5,7 +5,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.ir.code.If.Type; import com.android.tools.r8.ir.code.ValueTypeConstraint; @@ -83,8 +82,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 d30f023..5c1b2c4 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -60,8 +59,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 02722db..739b66f 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -64,8 +63,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 5ef18eb..bfcf0d3 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,6 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -53,8 +52,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 3019b9b..ead4920 100644 --- a/src/main/java/com/android/tools/r8/code/Format31c.java +++ b/src/main/java/com/android/tools/r8/code/Format31c.java
@@ -6,7 +6,6 @@ import static com.android.tools.r8.dex.Constants.U8BIT_MAX; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.ObjectToOffsetMapping; @@ -59,9 +58,8 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - BBBBBBBB.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + BBBBBBBB.collectIndexedItems(indexedItems); } @Override
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 192b28d..5e55ca4 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -54,8 +53,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 19de81f..d650fed 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -69,8 +68,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 4c70702..a31a494 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,6 @@ import static com.android.tools.r8.dex.Constants.U16BIT_MAX; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -62,8 +61,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // 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 f8c68c3..fba7d0d 100644 --- a/src/main/java/com/android/tools/r8/code/Format35c.java +++ b/src/main/java/com/android/tools/r8/code/Format35c.java
@@ -4,15 +4,13 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; 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 extends Base3Format { +public abstract class Format35c<T extends IndexedDexItem> extends Base3Format { public final byte A; public final byte C; @@ -20,10 +18,10 @@ public final byte E; public final byte F; public final byte G; - public IndexedDexItem BBBB; + public T BBBB; // A | G | op | BBBB | F | E | D | C - Format35c(int high, BytecodeStream stream, IndexedDexItem[] map) { + Format35c(int high, BytecodeStream stream, T[] map) { super(stream); G = (byte) (high & 0xf); A = (byte) ((high >> 4) & 0xf); @@ -36,7 +34,7 @@ D = (byte) ((next >> 4) & 0xf); } - protected Format35c(int A, IndexedDexItem BBBB, int C, int D, int E, int F, int G) { + Format35c(int A, T BBBB, int C, int D, int E, int F, int G) { assert 0 <= A && A <= Constants.U4BIT_MAX; assert 0 <= C && C <= Constants.U4BIT_MAX; assert 0 <= D && D <= Constants.U4BIT_MAX; @@ -111,12 +109,6 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - BBBB.collectIndexedItems(indexedItems, method, instructionOffset); - } - - @Override public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) { if (other == null || (this.getClass() != other.getClass())) { return false;
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 77d3571..a50a9d9 100644 --- a/src/main/java/com/android/tools/r8/code/Format3rc.java +++ b/src/main/java/com/android/tools/r8/code/Format3rc.java
@@ -4,29 +4,27 @@ package com.android.tools.r8.code; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; 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 extends Base3Format { +public abstract class Format3rc<T extends IndexedDexItem> extends Base3Format { public final short AA; public final char CCCC; - public IndexedDexItem BBBB; + public T BBBB; // AA | op | [meth|type]@BBBBB | CCCC - Format3rc(int high, BytecodeStream stream, IndexedDexItem[] map) { + Format3rc(int high, BytecodeStream stream, T[] map) { super(stream); this.AA = (short) high; this.BBBB = map[read16BitValue(stream)]; this.CCCC = read16BitValue(stream); } - Format3rc(int firstArgumentRegister, int argumentCount, IndexedDexItem dexItem) { + Format3rc(int firstArgumentRegister, int argumentCount, T dexItem) { assert 0 <= firstArgumentRegister && firstArgumentRegister <= Constants.U16BIT_MAX; assert 0 <= argumentCount && argumentCount <= Constants.U8BIT_MAX; this.CCCC = (char) firstArgumentRegister; @@ -34,6 +32,10 @@ BBBB = dexItem; } + public T getItem() { + return BBBB; + } + @Override public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { writeFirst(AA, dest); @@ -51,7 +53,7 @@ if (other == null || (this.getClass() != other.getClass())) { return false; } - Format3rc o = (Format3rc) other; + Format3rc<?> o = (Format3rc<?>) other; return o.AA == AA && o.CCCC == CCCC && o.BBBB.equals(BBBB); } @@ -89,17 +91,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - BBBB.collectIndexedItems(indexedItems, method, instructionOffset); - } - - @Override public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) { if (other == null || (this.getClass() != other.getClass())) { return false; } - Format3rc o = (Format3rc) other; + Format3rc<?> o = (Format3rc<?>) other; return o.AA == AA && o.CCCC == CCCC && equality.test(BBBB, o.BBBB); } }
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 fc88461..f5123cf 100644 --- a/src/main/java/com/android/tools/r8/code/Format45cc.java +++ b/src/main/java/com/android/tools/r8/code/Format45cc.java
@@ -87,10 +87,9 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - BBBB.collectIndexedItems(indexedItems, method, instructionOffset); - HHHH.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + BBBB.collectIndexedItems(indexedItems); + HHHH.collectIndexedItems(indexedItems); } @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 c139b03..0ec2780 100644 --- a/src/main/java/com/android/tools/r8/code/Format4rcc.java +++ b/src/main/java/com/android/tools/r8/code/Format4rcc.java
@@ -93,10 +93,9 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - BBBB.collectIndexedItems(indexedItems, method, instructionOffset); - HHHH.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + BBBB.collectIndexedItems(indexedItems); + HHHH.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 008e724..0e9ad93 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,6 @@ import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.naming.ClassNameMapper; import java.nio.ShortBuffer; @@ -54,8 +53,7 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { // No references. } }
diff --git a/src/main/java/com/android/tools/r8/code/Iget.java b/src/main/java/com/android/tools/r8/code/Iget.java index 65ebb44..3625037 100644 --- a/src/main/java/com/android/tools/r8/code/Iget.java +++ b/src/main/java/com/android/tools/r8/code/Iget.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class Iget extends Format22c { +public class Iget extends IgetOrIput { public static final int OPCODE = 0x52; public static final String NAME = "Iget"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstanceGet(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IgetBoolean.java b/src/main/java/com/android/tools/r8/code/IgetBoolean.java index 756969c..0df2731 100644 --- a/src/main/java/com/android/tools/r8/code/IgetBoolean.java +++ b/src/main/java/com/android/tools/r8/code/IgetBoolean.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IgetBoolean extends Format22c { +public class IgetBoolean extends IgetOrIput { public static final int OPCODE = 0x55; public static final String NAME = "IgetBoolean"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstanceGet(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IgetByte.java b/src/main/java/com/android/tools/r8/code/IgetByte.java index 56a239a..f3cb157 100644 --- a/src/main/java/com/android/tools/r8/code/IgetByte.java +++ b/src/main/java/com/android/tools/r8/code/IgetByte.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IgetByte extends Format22c { +public class IgetByte extends IgetOrIput { public static final int OPCODE = 0x56; public static final String NAME = "IgetByte"; @@ -41,10 +41,6 @@ public void registerUse(UseRegistry registry) { registry.registerInstanceFieldRead(getField()); } - @Override - public DexField getField() { - return (DexField) CCCC; - } @Override public void buildIR(IRBuilder builder) {
diff --git a/src/main/java/com/android/tools/r8/code/IgetChar.java b/src/main/java/com/android/tools/r8/code/IgetChar.java index ad9c44e..2c0793c 100644 --- a/src/main/java/com/android/tools/r8/code/IgetChar.java +++ b/src/main/java/com/android/tools/r8/code/IgetChar.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IgetChar extends Format22c { +public class IgetChar extends IgetOrIput { public static final int OPCODE = 0x57; public static final String NAME = "IgetChar"; @@ -41,10 +41,6 @@ public void registerUse(UseRegistry registry) { registry.registerInstanceFieldRead(getField()); } - @Override - public DexField getField() { - return (DexField) CCCC; - } @Override public void buildIR(IRBuilder builder) {
diff --git a/src/main/java/com/android/tools/r8/code/IgetObject.java b/src/main/java/com/android/tools/r8/code/IgetObject.java index d0c7c00..802409e 100644 --- a/src/main/java/com/android/tools/r8/code/IgetObject.java +++ b/src/main/java/com/android/tools/r8/code/IgetObject.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IgetObject extends Format22c { +public class IgetObject extends IgetOrIput { public static final int OPCODE = 0x54; public static final String NAME = "IgetObject"; @@ -38,11 +38,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void registerUse(UseRegistry registry) { registry.registerInstanceFieldRead(getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IgetOrIput.java b/src/main/java/com/android/tools/r8/code/IgetOrIput.java new file mode 100644 index 0000000..7800ace --- /dev/null +++ b/src/main/java/com/android/tools/r8/code/IgetOrIput.java
@@ -0,0 +1,28 @@ +// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.code; + +import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.DexField; + +public abstract class IgetOrIput extends Format22c<DexField> { + + IgetOrIput(int high, BytecodeStream stream, DexField[] map) { + super(high, stream, map); + } + + IgetOrIput(int A, int B, DexField CCCC) { + super(A, B, CCCC); + } + + @Override + public final void collectIndexedItems(IndexedItemCollection indexedItems) { + getField().collectIndexedItems(indexedItems); + } + + @Override + public final DexField getField() { + return CCCC; + } +}
diff --git a/src/main/java/com/android/tools/r8/code/IgetShort.java b/src/main/java/com/android/tools/r8/code/IgetShort.java index 75a9752..a8ca9a7 100644 --- a/src/main/java/com/android/tools/r8/code/IgetShort.java +++ b/src/main/java/com/android/tools/r8/code/IgetShort.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IgetShort extends Format22c { +public class IgetShort extends IgetOrIput { public static final int OPCODE = 0x58; public static final String NAME = "IgetShort"; @@ -38,11 +38,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void registerUse(UseRegistry registry) { registry.registerInstanceFieldRead(getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IgetWide.java b/src/main/java/com/android/tools/r8/code/IgetWide.java index 9893911..bd63727 100644 --- a/src/main/java/com/android/tools/r8/code/IgetWide.java +++ b/src/main/java/com/android/tools/r8/code/IgetWide.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IgetWide extends Format22c { +public class IgetWide extends IgetOrIput { public static final int OPCODE = 0x53; public static final String NAME = "IgetWide"; @@ -38,11 +38,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void registerUse(UseRegistry registry) { registry.registerInstanceFieldRead(getField()); }
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 36d7a0b..05a9558 100644 --- a/src/main/java/com/android/tools/r8/code/InstanceOf.java +++ b/src/main/java/com/android/tools/r8/code/InstanceOf.java
@@ -3,12 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InstanceOf extends Format22c { +public class InstanceOf extends Format22c<DexType> { public static final int OPCODE = 0x20; public static final String NAME = "InstanceOf"; @@ -48,12 +49,17 @@ } @Override - public void registerUse(UseRegistry registry) { - registry.registerInstanceOf(getType()); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); } public DexType getType() { - return (DexType) CCCC; + return CCCC; + } + + @Override + public void registerUse(UseRegistry registry) { + registry.registerInstanceOf(getType()); } @Override
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 9d93b40..d8accd7 100644 --- a/src/main/java/com/android/tools/r8/code/Instruction.java +++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -24,7 +24,7 @@ public final static int[] NO_TARGETS = null; public final static int[] EXIT_TARGET = {}; - public int offset; + private int offset; Instruction(BytecodeStream stream) { // When this constructor is invoked, we have already read 1 ushort from the stream. @@ -311,8 +311,7 @@ public abstract void write(ShortBuffer buffer, ObjectToOffsetMapping mapping); - public abstract void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset); + public abstract void collectIndexedItems(IndexedItemCollection indexedItems); 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 171aef2..72d0adb 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeCustom.java +++ b/src/main/java/com/android/tools/r8/code/InvokeCustom.java
@@ -3,13 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexCallSite; -import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeCustom extends Format35c { +public class InvokeCustom extends Format35c<DexCallSite> { public static final int OPCODE = 0xfc; public static final String NAME = "InvokeCustom"; @@ -19,7 +19,7 @@ super(high, stream, mapping.getCallSiteMap()); } - public InvokeCustom(int A, IndexedDexItem BBBB, int C, int D, int E, int F, int G) { + public InvokeCustom(int A, DexCallSite BBBB, int C, int D, int E, int F, int G) { super(A, BBBB, C, D, E, F, G); } @@ -39,13 +39,18 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getCallSite().collectIndexedItems(indexedItems); + } + + @Override public void registerUse(UseRegistry registry) { registry.registerCallSite(getCallSite()); } @Override public DexCallSite getCallSite() { - return (DexCallSite) BBBB; + return BBBB; } @Override
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 3aa60fc..ae63c4d 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
@@ -3,12 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeCustomRange extends Format3rc { +public class InvokeCustomRange extends Format3rc<DexCallSite> { public static final int OPCODE = 0xfd; public static final String NAME = "InvokeCustomRange"; @@ -38,8 +39,13 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getCallSite().collectIndexedItems(indexedItems); + } + + @Override public DexCallSite getCallSite() { - return (DexCallSite) BBBB; + return BBBB; } @Override
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 08d6826..cd8c1b7 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeDirect.java +++ b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
@@ -4,13 +4,12 @@ package com.android.tools.r8.code; import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeDirect extends Format35c { +public class InvokeDirect extends InvokeMethod { public static final int OPCODE = 0x70; public static final String NAME = "InvokeDirect"; @@ -20,7 +19,7 @@ super(high, stream, mapping.getMethodMap()); } - public InvokeDirect(int A, IndexedDexItem BBBB, int C, int D, int E, int F, int G) { + public InvokeDirect(int A, DexMethod BBBB, int C, int D, int E, int F, int G) { super(A, BBBB, C, D, E, F, G); } @@ -45,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRegisters(Type.DIRECT, getMethod(), getProto(), A, new int[]{C, D, E, F, G}); }
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 8f72a2b..41070dd 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeDirectRange extends Format3rc { +public class InvokeDirectRange extends InvokeMethodRange { public static final int OPCODE = 0x76; public static final String NAME = "InvokeDirectRange"; @@ -39,11 +39,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void registerUse(UseRegistry registry) { registry.registerInvokeDirect(getMethod()); }
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 b98af41..3e172e2 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeInterface.java +++ b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
@@ -4,13 +4,12 @@ package com.android.tools.r8.code; import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeInterface extends Format35c { +public class InvokeInterface extends InvokeMethod { public static final int OPCODE = 0x72; public static final String NAME = "InvokeInterface"; @@ -20,7 +19,7 @@ super(high, stream, mapping.getMethodMap()); } - public InvokeInterface(int A, IndexedDexItem BBBB, int C, int D, int E, int F, int G) { + public InvokeInterface(int A, DexMethod BBBB, int C, int D, int E, int F, int G) { super(A, BBBB, C, D, E, F, G); } @@ -45,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRegisters( Type.INTERFACE, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
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 e4d63b4..2d1986c 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeInterfaceRange extends Format3rc { +public class InvokeInterfaceRange extends InvokeMethodRange { public static final int OPCODE = 0x78; public static final String NAME = "InvokeInterfaceRange"; @@ -44,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRange(Type.INTERFACE, getMethod(), getProto(), AA, CCCC); }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/code/InvokeMethod.java new file mode 100644 index 0000000..cab1eac --- /dev/null +++ b/src/main/java/com/android/tools/r8/code/InvokeMethod.java
@@ -0,0 +1,28 @@ +// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.code; + +import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.DexMethod; + +public abstract class InvokeMethod extends Format35c<DexMethod> { + + InvokeMethod(int high, BytecodeStream stream, DexMethod[] map) { + super(high, stream, map); + } + + InvokeMethod(int A, DexMethod BBBB, int C, int D, int E, int F, int G) { + super(A, BBBB, C, D, E, F, G); + } + + @Override + public final void collectIndexedItems(IndexedItemCollection indexedItems) { + getMethod().collectIndexedItems(indexedItems); + } + + @Override + public final DexMethod getMethod() { + return BBBB; + } +}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java new file mode 100644 index 0000000..25fad42 --- /dev/null +++ b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
@@ -0,0 +1,28 @@ +// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.code; + +import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.DexMethod; + +public abstract class InvokeMethodRange extends Format3rc<DexMethod> { + + InvokeMethodRange(int high, BytecodeStream stream, DexMethod[] map) { + super(high, stream, map); + } + + InvokeMethodRange(int firstArgumentRegister, int argumentCount, DexMethod dexItem) { + super(firstArgumentRegister, argumentCount, dexItem); + } + + @Override + public final void collectIndexedItems(IndexedItemCollection indexedItems) { + getMethod().collectIndexedItems(indexedItems); + } + + @Override + public final DexMethod getMethod() { + return BBBB; + } +}
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 73cb887..531105b 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeStatic.java +++ b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeStatic extends Format35c { +public class InvokeStatic extends InvokeMethod { public static final int OPCODE = 0x71; public static final String NAME = "InvokeStatic"; @@ -44,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRegisters(Type.STATIC, getMethod(), getProto(), A, new int[]{C, D, E, F, G}); }
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 6fd3f42..7d3ff3d 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeStaticRange extends Format3rc { +public class InvokeStaticRange extends InvokeMethodRange { public static final int OPCODE = 0x77; public static final String NAME = "InvokeStaticRange"; @@ -44,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRange(Type.STATIC, getMethod(), getProto(), AA, CCCC); }
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 9575ed9..1dc8ac6 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeSuper.java +++ b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
@@ -4,13 +4,12 @@ package com.android.tools.r8.code; import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeSuper extends Format35c { +public class InvokeSuper extends InvokeMethod { public static final int OPCODE = 0x6f; public static final String NAME = "InvokeSuper"; @@ -20,7 +19,7 @@ super(high, stream, mapping.getMethodMap()); } - public InvokeSuper(int A, IndexedDexItem BBBB, int C, int D, int E, int F, int G) { + public InvokeSuper(int A, DexMethod BBBB, int C, int D, int E, int F, int G) { super(A, BBBB, C, D, E, F, G); } @@ -45,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRegisters(Type.SUPER, getMethod(), getProto(), A, new int[]{C, D, E, F, G}); }
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 63c6318..af6ebe8 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeSuperRange extends Format3rc { +public class InvokeSuperRange extends InvokeMethodRange { public static final int OPCODE = 0x75; public static final String NAME = "InvokeSuperRange"; @@ -44,11 +44,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRange(Type.SUPER, getMethod(), getProto(), AA, CCCC); }
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 b35882b..17596a4 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java +++ b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeVirtual extends Format35c { +public class InvokeVirtual extends InvokeMethod { public static final int OPCODE = 0x6e; public static final String NAME = "InvokeVirtual"; @@ -54,11 +54,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRegisters(Type.VIRTUAL, getMethod(), getProto(), A, new int[]{C, D, E, F, G}); }
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 cd78458..c2a0d6c 100644 --- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java +++ b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.conversion.IRBuilder; -public class InvokeVirtualRange extends Format3rc { +public class InvokeVirtualRange extends InvokeMethodRange { public static final int OPCODE = 0x74; public static final String NAME = "InvokeVirtualRange"; @@ -54,11 +54,6 @@ } @Override - public DexMethod getMethod() { - return (DexMethod) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInvokeRange(Type.VIRTUAL, getMethod(), getProto(), AA, CCCC); }
diff --git a/src/main/java/com/android/tools/r8/code/Iput.java b/src/main/java/com/android/tools/r8/code/Iput.java index eabfb2b..ea170c7 100644 --- a/src/main/java/com/android/tools/r8/code/Iput.java +++ b/src/main/java/com/android/tools/r8/code/Iput.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class Iput extends Format22c { +public class Iput extends IgetOrIput { public static final int OPCODE = 0x59; public static final String NAME = "Iput"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IputBoolean.java b/src/main/java/com/android/tools/r8/code/IputBoolean.java index 6276441..8a992c7 100644 --- a/src/main/java/com/android/tools/r8/code/IputBoolean.java +++ b/src/main/java/com/android/tools/r8/code/IputBoolean.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IputBoolean extends Format22c { +public class IputBoolean extends IgetOrIput { public static final int OPCODE = 0x5c; public static final String NAME = "IputBoolean"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IputByte.java b/src/main/java/com/android/tools/r8/code/IputByte.java index e333a9f..4005875 100644 --- a/src/main/java/com/android/tools/r8/code/IputByte.java +++ b/src/main/java/com/android/tools/r8/code/IputByte.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IputByte extends Format22c { +public class IputByte extends IgetOrIput { public static final int OPCODE = 0x5d; public static final String NAME = "IputByte"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IputChar.java b/src/main/java/com/android/tools/r8/code/IputChar.java index f4902ee..55f72fe 100644 --- a/src/main/java/com/android/tools/r8/code/IputChar.java +++ b/src/main/java/com/android/tools/r8/code/IputChar.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IputChar extends Format22c { +public class IputChar extends IgetOrIput { public static final int OPCODE = 0x5e; public static final String NAME = "IputChar"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IputObject.java b/src/main/java/com/android/tools/r8/code/IputObject.java index 7532340..5ca2f90 100644 --- a/src/main/java/com/android/tools/r8/code/IputObject.java +++ b/src/main/java/com/android/tools/r8/code/IputObject.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IputObject extends Format22c { +public class IputObject extends IgetOrIput { public static final int OPCODE = 0x5b; public static final String NAME = "IputObject"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IputShort.java b/src/main/java/com/android/tools/r8/code/IputShort.java index f0d4308..bf41801 100644 --- a/src/main/java/com/android/tools/r8/code/IputShort.java +++ b/src/main/java/com/android/tools/r8/code/IputShort.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IputShort extends Format22c { +public class IputShort extends IgetOrIput { public static final int OPCODE = 0x5f; public static final String NAME = "IputShort"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/IputWide.java b/src/main/java/com/android/tools/r8/code/IputWide.java index 68d09a6..4462875 100644 --- a/src/main/java/com/android/tools/r8/code/IputWide.java +++ b/src/main/java/com/android/tools/r8/code/IputWide.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class IputWide extends Format22c { +public class IputWide extends IgetOrIput { public static final int OPCODE = 0x5a; public static final String NAME = "IputWide"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) CCCC; - } - - @Override public void buildIR(IRBuilder builder) { builder.addInstancePut(A, B, getField()); }
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 0cce39f..dfb4ccb 100644 --- a/src/main/java/com/android/tools/r8/code/NewArray.java +++ b/src/main/java/com/android/tools/r8/code/NewArray.java
@@ -3,12 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class NewArray extends Format22c { +public class NewArray extends Format22c<DexType> { public static final int OPCODE = 0x23; public static final String NAME = "NewArray"; @@ -38,12 +39,17 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); + } + + @Override public void registerUse(UseRegistry registry) { registry.registerTypeReference(getType()); } public DexType getType() { - return (DexType) CCCC; + return CCCC; } @Override
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 31b8f68..695ae96 100644 --- a/src/main/java/com/android/tools/r8/code/NewInstance.java +++ b/src/main/java/com/android/tools/r8/code/NewInstance.java
@@ -3,12 +3,13 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.code; +import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class NewInstance extends Format21c { +public class NewInstance extends Format21c<DexType> { public static final int OPCODE = 0x22; public static final String NAME = "NewInstance"; @@ -38,6 +39,11 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + getType().collectIndexedItems(indexedItems); + } + + @Override public void registerUse(UseRegistry registry) { registry.registerNewInstance(getType()); }
diff --git a/src/main/java/com/android/tools/r8/code/Sget.java b/src/main/java/com/android/tools/r8/code/Sget.java index 3347fdd..0c727ac 100644 --- a/src/main/java/com/android/tools/r8/code/Sget.java +++ b/src/main/java/com/android/tools/r8/code/Sget.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class Sget extends Format21c { +public class Sget extends SgetOrSput { public static final int OPCODE = 0x60; public static final String NAME = "Sget"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SgetBoolean.java b/src/main/java/com/android/tools/r8/code/SgetBoolean.java index 27f18f2..3efb6b1 100644 --- a/src/main/java/com/android/tools/r8/code/SgetBoolean.java +++ b/src/main/java/com/android/tools/r8/code/SgetBoolean.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SgetBoolean extends Format21c { +public class SgetBoolean extends SgetOrSput { public static final int OPCODE = 0x63; public static final String NAME = "SgetBoolean"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SgetByte.java b/src/main/java/com/android/tools/r8/code/SgetByte.java index 3c0219b..9a40297 100644 --- a/src/main/java/com/android/tools/r8/code/SgetByte.java +++ b/src/main/java/com/android/tools/r8/code/SgetByte.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SgetByte extends Format21c { +public class SgetByte extends SgetOrSput { public static final int OPCODE = 0x64; public static final String NAME = "SgetByte"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SgetChar.java b/src/main/java/com/android/tools/r8/code/SgetChar.java index aa69c7f..429eaa6 100644 --- a/src/main/java/com/android/tools/r8/code/SgetChar.java +++ b/src/main/java/com/android/tools/r8/code/SgetChar.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SgetChar extends Format21c { +public class SgetChar extends SgetOrSput { public static final int OPCODE = 0x65; public static final String NAME = "SgetChar"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SgetObject.java b/src/main/java/com/android/tools/r8/code/SgetObject.java index f70da49..6b1130d 100644 --- a/src/main/java/com/android/tools/r8/code/SgetObject.java +++ b/src/main/java/com/android/tools/r8/code/SgetObject.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SgetObject extends Format21c { +public class SgetObject extends SgetOrSput { public static final int OPCODE = 0x62; public static final String NAME = "SgetObject"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SgetOrSput.java b/src/main/java/com/android/tools/r8/code/SgetOrSput.java new file mode 100644 index 0000000..d04e098 --- /dev/null +++ b/src/main/java/com/android/tools/r8/code/SgetOrSput.java
@@ -0,0 +1,28 @@ +// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.code; + +import com.android.tools.r8.dex.IndexedItemCollection; +import com.android.tools.r8.graph.DexField; + +abstract class SgetOrSput extends Format21c<DexField> { + + SgetOrSput(int high, BytecodeStream stream, DexField[] map) { + super(high, stream, map); + } + + protected SgetOrSput(int AA, DexField BBBB) { + super(AA, BBBB); + } + + @Override + public final void collectIndexedItems(IndexedItemCollection indexedItems) { + getField().collectIndexedItems(indexedItems); + } + + @Override + public final DexField getField() { + return BBBB; + } +}
diff --git a/src/main/java/com/android/tools/r8/code/SgetShort.java b/src/main/java/com/android/tools/r8/code/SgetShort.java index 0149fb4..37f331e 100644 --- a/src/main/java/com/android/tools/r8/code/SgetShort.java +++ b/src/main/java/com/android/tools/r8/code/SgetShort.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SgetShort extends Format21c { +public class SgetShort extends SgetOrSput { public static final int OPCODE = 0x66; public static final String NAME = "SgetShort"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SgetWide.java b/src/main/java/com/android/tools/r8/code/SgetWide.java index ea008ad..638ca0c 100644 --- a/src/main/java/com/android/tools/r8/code/SgetWide.java +++ b/src/main/java/com/android/tools/r8/code/SgetWide.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SgetWide extends Format21c { +public class SgetWide extends SgetOrSput { public static final int OPCODE = 0x61; public static final String NAME = "SgetWide"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticGet(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/Sput.java b/src/main/java/com/android/tools/r8/code/Sput.java index 6885da6..e6f3b4e 100644 --- a/src/main/java/com/android/tools/r8/code/Sput.java +++ b/src/main/java/com/android/tools/r8/code/Sput.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class Sput extends Format21c { +public class Sput extends SgetOrSput { public static final int OPCODE = 0x67; public static final String NAME = "Sput"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SputBoolean.java b/src/main/java/com/android/tools/r8/code/SputBoolean.java index 041ba02..6dae9b2 100644 --- a/src/main/java/com/android/tools/r8/code/SputBoolean.java +++ b/src/main/java/com/android/tools/r8/code/SputBoolean.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SputBoolean extends Format21c { +public class SputBoolean extends SgetOrSput { public static final int OPCODE = 0x6a; public static final String NAME = "SputBoolean"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SputByte.java b/src/main/java/com/android/tools/r8/code/SputByte.java index 87b79bd..c6cb521 100644 --- a/src/main/java/com/android/tools/r8/code/SputByte.java +++ b/src/main/java/com/android/tools/r8/code/SputByte.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SputByte extends Format21c { +public class SputByte extends SgetOrSput { public static final int OPCODE = 0x6b; public static final String NAME = "SputByte"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SputChar.java b/src/main/java/com/android/tools/r8/code/SputChar.java index 5fcd836..727ba25 100644 --- a/src/main/java/com/android/tools/r8/code/SputChar.java +++ b/src/main/java/com/android/tools/r8/code/SputChar.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SputChar extends Format21c { +public class SputChar extends SgetOrSput { public static final int OPCODE = 0x6c; public static final String NAME = "SputChar"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SputObject.java b/src/main/java/com/android/tools/r8/code/SputObject.java index fa661ea..4850664 100644 --- a/src/main/java/com/android/tools/r8/code/SputObject.java +++ b/src/main/java/com/android/tools/r8/code/SputObject.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SputObject extends Format21c { +public class SputObject extends SgetOrSput { public static final int OPCODE = 0x69; public static final String NAME = "SputObject"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SputShort.java b/src/main/java/com/android/tools/r8/code/SputShort.java index d2b5f85..eb33e33 100644 --- a/src/main/java/com/android/tools/r8/code/SputShort.java +++ b/src/main/java/com/android/tools/r8/code/SputShort.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SputShort extends Format21c { +public class SputShort extends SgetOrSput { public static final int OPCODE = 0x6d; public static final String NAME = "SputShort"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
diff --git a/src/main/java/com/android/tools/r8/code/SputWide.java b/src/main/java/com/android/tools/r8/code/SputWide.java index 7e6aeaa..8104f75 100644 --- a/src/main/java/com/android/tools/r8/code/SputWide.java +++ b/src/main/java/com/android/tools/r8/code/SputWide.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.graph.UseRegistry; import com.android.tools.r8.ir.conversion.IRBuilder; -public class SputWide extends Format21c { +public class SputWide extends SgetOrSput { public static final int OPCODE = 0x68; public static final String NAME = "SputWide"; @@ -43,11 +43,6 @@ } @Override - public DexField getField() { - return (DexField) BBBB; - } - - @Override public void buildIR(IRBuilder builder) { builder.addStaticPut(AA, getField()); }
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 f0e8da6..21b5cd4 100644 --- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -14,6 +14,7 @@ import com.android.tools.r8.DexIndexedConsumer; import com.android.tools.r8.ProgramConsumer; import com.android.tools.r8.ResourceException; +import com.android.tools.r8.code.Instruction; import com.android.tools.r8.dex.FileWriter.ByteBufferResult; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.features.FeatureSplitConfiguration.DataResourceProvidersAndConsumer; @@ -23,6 +24,7 @@ import com.android.tools.r8.graph.DexAnnotationDirectory; import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexApplication; +import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.DexCode; import com.android.tools.r8.graph.DexDebugInfo; import com.android.tools.r8.graph.DexEncodedArray; @@ -251,6 +253,11 @@ // TODO(b/151313715): Move this to the writer threads. insertAttributeAnnotations(); + // Each DexCallSite must have its instruction offset set for sorting. + if (options.isGeneratingDex()) { + setCallSiteContexts(executorService); + } + // Generate the dex file contents. List<Future<Boolean>> dexDataFutures = new ArrayList<>(); List<VirtualFile> virtualFiles = distribute(executorService); @@ -526,6 +533,26 @@ } } + private void setCallSiteContexts(ExecutorService executorService) throws ExecutionException { + ThreadUtils.processItems( + appView.appInfo().classes(), this::setCallSiteContexts, executorService); + } + + private void setCallSiteContexts(DexProgramClass clazz) { + for (DexEncodedMethod method : clazz.methods()) { + if (method.hasCode()) { + DexCode code = method.getCode().asDexCode(); + assert code != null; + for (Instruction instruction : code.instructions) { + DexCallSite callSite = instruction.getCallSite(); + if (callSite != null) { + callSite.setContext(method.getReference(), instruction.getOffset()); + } + } + } + } + } + /** * Rewrites the code for all methods in the given file so that they use JumboString for at least * the strings that require it in mapping.
diff --git a/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java b/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java index 45b8bfe..273bf3b 100644 --- a/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java +++ b/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.IndexedDexItem; import com.android.tools.r8.graph.InitClassLens; @@ -100,6 +101,10 @@ */ boolean addMethodHandle(DexMethodHandle methodHandle); + default GraphLens getGraphLens() { + return GraphLens.getIdentityLens(); + } + default InitClassLens getInitClassLens() { return InitClassLens.getDefault(); }
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 e623f5e..709eb9d 100644 --- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java +++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.ThreadUtils; @@ -70,7 +71,7 @@ public void updateNumbersOfIds() { // Use a temporary VirtualFile to evaluate the number of ids in the group. - VirtualFile virtualFile = new VirtualFile(0, initClassLens, namingLens); + VirtualFile virtualFile = new VirtualFile(0, graphLens, initClassLens, namingLens); // Note: sort not needed. for (DexProgramClass clazz : members) { virtualFile.addClass(clazz); @@ -284,6 +285,7 @@ private final Set<DexProgramClass> classes; private final DexApplication app; private int dexIndexOffset; + private final GraphLens graphLens; private final InitClassLens initClassLens; private final NamingLens namingLens; private final DirectSubClassesInfo directSubClasses; @@ -293,6 +295,7 @@ List<VirtualFile> dexes, Set<DexProgramClass> classes, int dexIndexOffset, + GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, DexApplication app, @@ -301,6 +304,7 @@ this.dexes = dexes; this.classes = classes; this.dexIndexOffset = dexIndexOffset; + this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; this.app = app; @@ -374,7 +378,7 @@ private Collection<VirtualFile> assignGroup(ClassGroup group, List<VirtualFile> dexBlackList) { VirtualFileCycler cycler = - new VirtualFileCycler(dexes, initClassLens, namingLens, dexIndexOffset); + new VirtualFileCycler(dexes, graphLens, initClassLens, namingLens, dexIndexOffset); if (group.members.isEmpty()) { return Collections.emptyList(); } else if (group.canFitInOneDex()) { @@ -423,7 +427,7 @@ Collection<VirtualFile> usedDex = new ArrayList<>(); VirtualFileCycler cycler = - new VirtualFileCycler(dexes, initClassLens, namingLens, dexIndexOffset); + new VirtualFileCycler(dexes, 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);
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 a419f4a..b036d96 100644 --- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java +++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; import com.android.tools.r8.graph.ObjectToOffsetMapping; import com.android.tools.r8.logging.Log; @@ -76,29 +77,39 @@ private final DexProgramClass primaryClass; - VirtualFile(int id, InitClassLens initClassLens, NamingLens namingLens) { - this(id, initClassLens, namingLens, null, null); + VirtualFile(int id, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens) { + this(id, graphLens, initClassLens, namingLens, null, null); } VirtualFile( - int id, InitClassLens initClassLens, NamingLens namingLens, FeatureSplit featureSplit) { - this(id, initClassLens, namingLens, null, featureSplit); - } - - private VirtualFile( - int id, InitClassLens initClassLens, NamingLens namingLens, DexProgramClass primaryClass) { - this(id, initClassLens, namingLens, primaryClass, null); + int id, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + FeatureSplit featureSplit) { + this(id, graphLens, initClassLens, namingLens, null, featureSplit); } private VirtualFile( int id, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens, + DexProgramClass primaryClass) { + this(id, graphLens, initClassLens, namingLens, primaryClass, null); + } + + private VirtualFile( + int id, + GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, DexProgramClass primaryClass, FeatureSplit featureSplit) { this.id = id; - this.indexedItems = new VirtualFileIndexedItemCollection(initClassLens, namingLens); - this.transaction = new IndexedItemTransaction(indexedItems, initClassLens, namingLens); + this.indexedItems = new VirtualFileIndexedItemCollection(graphLens, initClassLens, namingLens); + this.transaction = + new IndexedItemTransaction(indexedItems, graphLens, initClassLens, namingLens); this.primaryClass = primaryClass; this.featureSplit = featureSplit; } @@ -296,7 +307,12 @@ for (DexProgramClass clazz : application.classes()) { if (!combineSyntheticClassesWithPrimaryClass || clazz.getSynthesizedFrom().isEmpty()) { VirtualFile file = - new VirtualFile(virtualFiles.size(), writer.initClassLens, writer.namingLens, clazz); + new VirtualFile( + virtualFiles.size(), + writer.graphLens, + writer.initClassLens, + writer.namingLens, + clazz); virtualFiles.add(file); file.addClass(clazz); files.put(clazz, file); @@ -329,7 +345,7 @@ this.options = options; // Create the primary dex file. The distribution will add more if needed. - mainDexFile = new VirtualFile(0, writer.initClassLens, writer.namingLens); + mainDexFile = new VirtualFile(0, writer.graphLens, writer.initClassLens, writer.namingLens); assert virtualFiles.isEmpty(); virtualFiles.add(mainDexFile); addMarkers(mainDexFile); @@ -447,7 +463,11 @@ // Add a new virtual file, start from index 0 again VirtualFile featureFile = new VirtualFile( - 0, writer.initClassLens, writer.namingLens, featureSplitSetEntry.getKey()); + 0, + writer.graphLens, + writer.initClassLens, + writer.namingLens, + featureSplitSetEntry.getKey()); virtualFiles.add(featureFile); addMarkers(featureFile); Set<DexProgramClass> featureClasses = @@ -461,6 +481,7 @@ application.dexItemFactory, fillStrategy, 0, + writer.graphLens, writer.initClassLens, writer.namingLens, options) @@ -497,7 +518,8 @@ assert !virtualFiles.get(0).isEmpty(); 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.initClassLens, writer.namingLens)); + virtualFiles.add( + new VirtualFile(1, writer.graphLens, writer.initClassLens, writer.namingLens)); filesForDistribution = virtualFiles.subList(1, virtualFiles.size()); fileIndexOffset = 1; } @@ -511,6 +533,7 @@ filesForDistribution, classes, fileIndexOffset, + writer.graphLens, writer.initClassLens, writer.namingLens, writer.application, @@ -527,6 +550,7 @@ application.dexItemFactory, fillStrategy, fileIndexOffset, + writer.graphLens, writer.initClassLens, writer.namingLens, options) @@ -566,6 +590,7 @@ private static class VirtualFileIndexedItemCollection implements IndexedItemCollection { + private final GraphLens graphLens; private final InitClassLens initClassLens; private final NamingLens namingLens; @@ -578,7 +603,9 @@ private final Set<DexCallSite> callSites = Sets.newIdentityHashSet(); private final Set<DexMethodHandle> methodHandles = Sets.newIdentityHashSet(); - public VirtualFileIndexedItemCollection(InitClassLens initClassLens, NamingLens namingLens) { + public VirtualFileIndexedItemCollection( + GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens) { + this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; } @@ -636,6 +663,11 @@ } @Override + public GraphLens getGraphLens() { + return graphLens; + } + + @Override public InitClassLens getInitClassLens() { return initClassLens; } @@ -660,6 +692,7 @@ public static class IndexedItemTransaction implements IndexedItemCollection { private final VirtualFileIndexedItemCollection base; + private final GraphLens graphLens; private final InitClassLens initClassLens; private final NamingLens namingLens; @@ -673,8 +706,12 @@ private final Set<DexMethodHandle> methodHandles = new LinkedHashSet<>(); private IndexedItemTransaction( - VirtualFileIndexedItemCollection base, InitClassLens initClassLens, NamingLens namingLens) { + VirtualFileIndexedItemCollection base, + GraphLens graphLens, + InitClassLens initClassLens, + NamingLens namingLens) { this.base = base; + this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; } @@ -732,6 +769,11 @@ } @Override + public GraphLens getGraphLens() { + return graphLens; + } + + @Override public InitClassLens getInitClassLens() { return initClassLens; } @@ -813,6 +855,7 @@ static class VirtualFileCycler { private final List<VirtualFile> files; + private final GraphLens graphLens; private final InitClassLens initClassLens; private final NamingLens namingLens; @@ -823,10 +866,12 @@ VirtualFileCycler( List<VirtualFile> files, + GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, int fileIndexOffset) { this.files = files; + this.graphLens = graphLens; this.initClassLens = initClassLens; this.namingLens = namingLens; @@ -859,7 +904,7 @@ return activeFiles.next(); } else { VirtualFile newFile = - new VirtualFile(nextFileId++, initClassLens, namingLens, featuresplit); + new VirtualFile(nextFileId++, graphLens, initClassLens, namingLens, featuresplit); files.add(newFile); allFilesCyclic = Iterators.cycle(files); return newFile; @@ -890,7 +935,8 @@ } VirtualFile addFile() { - VirtualFile newFile = new VirtualFile(nextFileId++, initClassLens, namingLens, featuresplit); + VirtualFile newFile = + new VirtualFile(nextFileId++, graphLens, initClassLens, namingLens, featuresplit); files.add(newFile); reset(); @@ -936,6 +982,7 @@ DexItemFactory dexItemFactory, FillStrategy fillStrategy, int fileIndexOffset, + GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens, InternalOptions options) { @@ -944,7 +991,8 @@ this.dexItemFactory = dexItemFactory; this.fillStrategy = fillStrategy; this.options = options; - this.cycler = new VirtualFileCycler(files, initClassLens, namingLens, fileIndexOffset); + this.cycler = + new VirtualFileCycler(files, graphLens, initClassLens, namingLens, fileIndexOffset); } static boolean coveredByPrefix(String originalName, String currentPrefix) {
diff --git a/src/main/java/com/android/tools/r8/errors/InternalCompilerError.java b/src/main/java/com/android/tools/r8/errors/InternalCompilerError.java index a5080d3..be068d9 100644 --- a/src/main/java/com/android/tools/r8/errors/InternalCompilerError.java +++ b/src/main/java/com/android/tools/r8/errors/InternalCompilerError.java
@@ -6,9 +6,12 @@ /** * Exception to signal an unexpected state internally to the compiler. * - * Exceptions of this type always represent an bug in the compiler. - * For expected errors, such as invalid input, the compiler should generate a CompilationError. - */ + * <p>Exceptions of this type always represent an bug in the compiler. + * + * <p>For expected errors, such as invalid input, the compiler should generate a CompilationError. + * + * <p>For internal recoverable exceptions (eg, control operators) this base should not be used. + */ public class InternalCompilerError extends IllegalStateException { public InternalCompilerError() {
diff --git a/src/main/java/com/android/tools/r8/errors/InvalidDebugInfoException.java b/src/main/java/com/android/tools/r8/errors/InvalidDebugInfoException.java index f3f99e2..faf93cd 100644 --- a/src/main/java/com/android/tools/r8/errors/InvalidDebugInfoException.java +++ b/src/main/java/com/android/tools/r8/errors/InvalidDebugInfoException.java
@@ -3,7 +3,8 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.errors; -public class InvalidDebugInfoException extends InternalCompilerError { +/** An always caught exception to abort/restart IR construction due to invalid locals. */ +public class InvalidDebugInfoException extends RuntimeException { public InvalidDebugInfoException(String message) { super(message); }
diff --git a/src/main/java/com/android/tools/r8/errors/InvalidDescriptorException.java b/src/main/java/com/android/tools/r8/errors/InvalidDescriptorException.java index f6702b7..1b426bc 100644 --- a/src/main/java/com/android/tools/r8/errors/InvalidDescriptorException.java +++ b/src/main/java/com/android/tools/r8/errors/InvalidDescriptorException.java
@@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.errors; -public class InvalidDescriptorException extends InternalCompilerError { +public class InvalidDescriptorException extends RuntimeException { public InvalidDescriptorException(String message) { super(message); }
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 66b00b8..59239db 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfo.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -115,9 +115,8 @@ return dependent; } DexClass definition = definitionFor(type); - if (definition != null && !definition.isLibraryClass() && dependent.isProgramClass()) { - InterfaceMethodRewriter.reportDependencyEdge( - dependent.asProgramClass(), definition, options()); + if (definition != null && !definition.isLibraryClass() && !dependent.isLibraryClass()) { + InterfaceMethodRewriter.reportDependencyEdge(dependent, definition, options()); } return definition; }
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 c6bc6b4..d0a3643 100644 --- a/src/main/java/com/android/tools/r8/graph/AppView.java +++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -478,6 +478,9 @@ } public OptionalBool isSubtype(DexType subtype, DexType supertype) { + // Even if we can compute isSubtype by having class hierarchy we may not be allowed to ask the + // question for all code paths in D8. Having the check for liveness ensure that we are in R8 + // territory. return appInfo().hasLiveness() ? OptionalBool.of(appInfo().withLiveness().isSubtype(subtype, supertype)) : OptionalBool.unknown();
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java index 318b1bc..c9e4d4d 100644 --- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java +++ b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.graph; import com.android.tools.r8.ir.code.Invoke; +import com.android.tools.r8.utils.MapUtils; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import java.util.IdentityHashMap; @@ -24,8 +25,11 @@ private final BiMap<DexType, DexType> originalTypeNames = HashBiMap.create(); private final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create(); private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create(); - private final Map<DexMethod, DexMethod> originalMethodSignaturesForBridges = - new IdentityHashMap<>(); + + // Original method signatures for bridges and companion methods. Due to the synthesis of these + // methods, the mapping from original methods to final methods is not one-to-one, but one-to-many, + // which is why we need an additional map. + private final Map<DexMethod, DexMethod> extraOriginalMethodSignatures = new IdentityHashMap<>(); public AppliedGraphLens(AppView<? extends AppInfoWithClassHierarchy> appView) { this.appView = appView; @@ -58,22 +62,24 @@ for (DexEncodedMethod encodedMethod : clazz.methods()) { DexMethod method = encodedMethod.method; DexMethod original = appView.graphLens().getOriginalMethodSignature(method); - if (original != method) { - DexMethod existing = originalMethodSignatures.inverse().get(original); - if (existing == null) { - originalMethodSignatures.put(method, original); + DexMethod existing = originalMethodSignatures.inverse().get(original); + if (existing == null) { + originalMethodSignatures.put(method, original); + } else { + DexMethod renamed = appView.graphLens().getRenamedMethodSignature(original); + if (renamed == existing) { + extraOriginalMethodSignatures.put(method, original); } else { - DexMethod renamed = getRenamedMethodSignature(original); - if (renamed == existing) { - originalMethodSignaturesForBridges.put(method, original); - } else { - originalMethodSignatures.forcePut(method, original); - originalMethodSignaturesForBridges.put(existing, original); - } + originalMethodSignatures.forcePut(method, original); + extraOriginalMethodSignatures.put(existing, original); } } } } + + // Trim original method signatures. + MapUtils.removeIdentityMappings(originalMethodSignatures); + MapUtils.removeIdentityMappings(extraOriginalMethodSignatures); } @Override @@ -88,8 +94,8 @@ @Override public DexMethod getOriginalMethodSignature(DexMethod method) { - if (originalMethodSignaturesForBridges.containsKey(method)) { - return originalMethodSignaturesForBridges.get(method); + if (extraOriginalMethodSignatures.containsKey(method)) { + return extraOriginalMethodSignatures.get(method); } return originalMethodSignatures.getOrDefault(method, method); }
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java index 16533fe..c40931a 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -204,12 +204,13 @@ NamingLens namingLens, AppView<?> appView, int classFileVersion) { + GraphLens graphLens = appView.graphLens(); InitClassLens initClassLens = appView.initClassLens(); InternalOptions options = appView.options(); CfLabel parameterLabel = null; if (shouldAddParameterNames(method, appView)) { parameterLabel = new CfLabel(); - parameterLabel.write(visitor, initClassLens, namingLens); + parameterLabel.write(visitor, graphLens, initClassLens, namingLens); } for (CfInstruction instruction : instructions) { if (instruction instanceof CfFrame @@ -217,7 +218,7 @@ || (classFileVersion == V1_6 && !options.shouldKeepStackMapTable()))) { continue; } - instruction.write(visitor, initClassLens, namingLens); + instruction.write(visitor, graphLens, initClassLens, namingLens); } visitor.visitEnd(); visitor.visitMaxs(maxStack, maxLocals);
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java index bb11c69..1f2a522 100644 --- a/src/main/java/com/android/tools/r8/graph/Code.java +++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -3,7 +3,6 @@ // 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.dex.MixedSectionCollection; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.ir.code.IRCode; @@ -89,12 +88,6 @@ } @Override - void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset) { - throw new Unreachable(); - } - - @Override void collectMixedSectionItems(MixedSectionCollection collection) { throw new Unreachable(); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java index a409737..ade8d06 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -62,10 +62,8 @@ return visibility + " " + annotation; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - annotation.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + annotation.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java index a6b7824..04f59d7 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -3,7 +3,6 @@ // 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.dex.MixedSectionCollection; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.naming.NamingLens; @@ -92,12 +91,6 @@ } @Override - public void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset) { - throw new Unreachable(); - } - - @Override public void collectMixedSectionItems(MixedSectionCollection collection) { throw new Unreachable(); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java index 10c6535..e1965be 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -39,11 +39,9 @@ return name + "=" + value; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - name.collectIndexedItems(indexedItems, method, instructionOffset); - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + name.collectIndexedItems(indexedItems); + value.collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java index 7371902..e13faf8 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -77,10 +77,10 @@ return false; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - collectAll(indexedItems, annotations); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + for (DexAnnotation annotation : annotations) { + annotation.collectIndexedItems(indexedItems); + } } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java index 8c76ca1..bcb8873 100644 --- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java +++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -35,7 +35,7 @@ // Only used for sorting for deterministic output. This is the method and the instruction // offset where this DexCallSite ends up in the output. private DexMethod method; - private int instructionOffset; + private int instructionOffset = -1; DexCallSite( DexString methodName, @@ -84,6 +84,15 @@ return application.getCallSite(name, desc, bootstrapMethod, bootstrapArgs); } + public void setContext(DexMethod method, int instructionOffset) { + assert method != null; + assert instructionOffset >= 0; + assert this.method == null; + assert this.instructionOffset == -1; + this.method = method; + this.instructionOffset = instructionOffset; + } + @Override public int computeHashCode() { // Call sites are equal only when this == other, which was already computed by the caller of @@ -115,23 +124,13 @@ return builder.toString(); } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - assert method != null; - // Since collectIndexedItems() is called in transactions that may be rolled back, we may end up - // setting this.method and this.instructionOffset more than once. If we do set them more than - // once, then we must have the same values for method and instructionOffset every time. - assert this.method == null || this.method == method; - assert this.instructionOffset == 0 || this.instructionOffset == instructionOffset; - this.method = method; - this.instructionOffset = instructionOffset; + public void collectIndexedItems(IndexedItemCollection indexedItems) { if (indexedItems.addCallSite(this)) { - methodName.collectIndexedItems(indexedItems, method, instructionOffset); - methodProto.collectIndexedItems(indexedItems, method, instructionOffset); - bootstrapMethod.collectIndexedItems(indexedItems, method, instructionOffset); + methodName.collectIndexedItems(indexedItems); + methodProto.collectIndexedItems(indexedItems); + bootstrapMethod.collectIndexedItems(indexedItems); for (DexValue arg : bootstrapArgs) { - arg.collectIndexedItems(indexedItems, method, instructionOffset); + arg.collectIndexedItems(indexedItems); } } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java index fe2eabd..528b79b 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -113,6 +113,10 @@ return accessFlags; } + public DexString getSourceFile() { + return sourceFile; + } + public Iterable<DexEncodedField> fields() { return fields(Predicates.alwaysTrue()); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java index 1e85690..118a04d 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -5,7 +5,6 @@ import com.android.tools.r8.ProgramResource; import com.android.tools.r8.ProgramResource.Kind; -import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.kotlin.KotlinClassLevelInfo; @@ -54,12 +53,6 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - throw new Unreachable(); - } - - @Override public String toString() { return type.toString() + "(classpath class)"; }
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 ae3fe1e..6716297 100644 --- a/src/main/java/com/android/tools/r8/graph/DexCode.java +++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -403,14 +403,11 @@ return builder.toString(); } - @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - assert instructionOffset == -1; + public void collectIndexedItems(IndexedItemCollection indexedItems) { highestSortingString = null; for (Instruction insn : instructions) { assert !insn.isDexItemBasedConstString(); - insn.collectIndexedItems(indexedItems, method, insn.getOffset()); + insn.collectIndexedItems(indexedItems); if (insn.isConstString()) { updateHighestSortingString(insn.asConstString().getString()); } else if (insn.isConstStringJumbo()) { @@ -512,12 +509,6 @@ } @Override - void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - // Intentionally left empty. - } - - @Override void collectMixedSectionItems(MixedSectionCollection mixedItems) { // Should never be visited. assert false; @@ -557,10 +548,10 @@ return false; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - collectAll(indexedItems, pairs); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + for (TypeAddrPair pair : pairs) { + pair.collectIndexedItems(indexedItems); + } } @Override @@ -599,10 +590,8 @@ this.addr = addr; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - type.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + type.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 059f7f6..20fd6e6 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java +++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -13,9 +13,7 @@ abstract public class DexDebugEvent extends DexItem { public static final DexDebugEvent[] EMPTY_ARRAY = {}; - @Override - public void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection collection) { // Empty by default. } @@ -222,16 +220,15 @@ } @Override - public void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection collection) { if (name != null) { - name.collectIndexedItems(collection, method, instructionOffset); + name.collectIndexedItems(collection); } if (type != null) { - type.collectIndexedItems(collection, method, instructionOffset); + type.collectIndexedItems(collection); } if (signature != null) { - signature.collectIndexedItems(collection, method, instructionOffset); + signature.collectIndexedItems(collection); } } @@ -362,9 +359,8 @@ } @Override - public void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset) { - fileName.collectIndexedItems(collection, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection collection) { + fileName.collectIndexedItems(collection); } @Override
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 9c27243..51ad23c 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java +++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -54,11 +54,15 @@ return false; } - @Override - public void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset) { - collectAll(collection, parameters); - collectAll(collection, events); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + for (DexString parameter : parameters) { + if (parameter != null) { + parameter.collectIndexedItems(indexedItems); + } + } + for (DexDebugEvent event : events) { + event.collectIndexedItems(indexedItems); + } } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java index f5c5272..0ed6769 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -23,11 +23,11 @@ this.elements = elements; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - type.collectIndexedItems(indexedItems, method, instructionOffset); - collectAll(indexedItems, elements); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + type.collectIndexedItems(indexedItems); + for (DexAnnotationElement element : elements) { + element.collectIndexedItems(indexedItems); + } } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java index fac96c9..19ec6c2 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
@@ -15,10 +15,10 @@ this.values = values; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - collectAll(indexedItems, values); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + for (DexValue value : values) { + value.collectIndexedItems(indexedItems); + } } @Override
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 5d9fa45..4b6fd50 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -87,13 +87,11 @@ this.kotlinMemberInfo = kotlinMemberInfo; } - @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - field.collectIndexedItems(indexedItems, method, instructionOffset); - annotations().collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + field.collectIndexedItems(indexedItems); + annotations().collectIndexedItems(indexedItems); if (accessFlags.isStatic()) { - getStaticValue().collectIndexedItems(indexedItems, method, instructionOffset); + getStaticValue().collectIndexedItems(indexedItems); } }
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 ff7e38c..ce6934a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -648,13 +648,15 @@ return "Encoded method " + method; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { checkIfObsolete(); this.method.collectIndexedItems(indexedItems); if (code != null) { - code.collectIndexedItems(indexedItems, this.method); + if (code.isDexCode()) { + code.asDexCode().collectIndexedItems(indexedItems); + } else { + assert false; + } } annotations().collectIndexedItems(indexedItems); parameterAnnotationsList.collectIndexedItems(indexedItems);
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java index 84d581e..19b793d 100644 --- a/src/main/java/com/android/tools/r8/graph/DexField.java +++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -79,13 +79,11 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { if (indexedItems.addField(this)) { - holder.collectIndexedItems(indexedItems, method, instructionOffset); - type.collectIndexedItems(indexedItems, method, instructionOffset); - indexedItems.getRenamedName(this).collectIndexedItems( - indexedItems, method, instructionOffset); + holder.collectIndexedItems(indexedItems); + type.collectIndexedItems(indexedItems); + indexedItems.getRenamedName(this).collectIndexedItems(indexedItems); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItem.java b/src/main/java/com/android/tools/r8/graph/DexItem.java index eb8e150..f26e41a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexItem.java +++ b/src/main/java/com/android/tools/r8/graph/DexItem.java
@@ -3,7 +3,6 @@ // 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.dex.MixedSectionCollection; import java.util.Collection; import java.util.function.Consumer; @@ -11,17 +10,13 @@ public abstract class DexItem { - static <T extends DexItem> void collectAll(IndexedItemCollection indexedItems, T[] items) { - consumeArray(items, (T item) -> item.collectIndexedItems(indexedItems)); - } - public static <T extends DexItem> void collectAll(MixedSectionCollection mixedItems, T[] items) { - consumeArray(items, (T item) -> item.collectMixedSectionItems(mixedItems)); + consumeArray(items, item -> item.collectMixedSectionItems(mixedItems)); } public static <T extends DexItem> void collectAll(MixedSectionCollection mixedItems, Collection<T> items) { - items.forEach((T item) -> item.collectMixedSectionItems(mixedItems)); + items.forEach(item -> item.collectMixedSectionItems(mixedItems)); } /** @@ -39,17 +34,6 @@ } } - abstract void collectIndexedItems(IndexedItemCollection collection, - DexMethod method, int instructionOffset); - - public void collectIndexedItems(IndexedItemCollection collection) { - collectIndexedItems(collection, null, -1); - } - - public void collectIndexedItems(IndexedItemCollection collection, DexMethod method) { - collectIndexedItems(collection, method, -1); - } - abstract void collectMixedSectionItems(MixedSectionCollection collection); protected void flushCachedValues() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java index 7711eb3..22920eb 100644 --- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -5,7 +5,6 @@ import com.android.tools.r8.ProgramResource; import com.android.tools.r8.ProgramResource.Kind; -import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.kotlin.KotlinClassLevelInfo; @@ -81,12 +80,6 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - throw new Unreachable(); - } - - @Override public String toString() { return type.toString() + "(library class)"; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java index d9868a5..5c9dad2 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java +++ b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
@@ -17,13 +17,6 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - item.collectIndexedItems(indexedItems, method, instructionOffset); - annotations.collectIndexedItems(indexedItems, method, instructionOffset); - } - - @Override void collectMixedSectionItems(MixedSectionCollection mixedItems) { annotations.collectMixedSectionItems(mixedItems); } @@ -50,6 +43,11 @@ public DexFieldAnnotation(DexField item, DexAnnotationSet annotations) { super(item, annotations); } + + public void collectIndexedItems(IndexedItemCollection indexedItems) { + item.collectIndexedItems(indexedItems); + annotations.collectIndexedItems(indexedItems); + } } public static class DexMethodAnnotation extends DexMemberAnnotation<DexMethod, DexAnnotationSet> { @@ -57,6 +55,11 @@ public DexMethodAnnotation(DexMethod item, DexAnnotationSet annotations) { super(item, annotations); } + + public void collectIndexedItems(IndexedItemCollection indexedItems) { + item.collectIndexedItems(indexedItems); + annotations.collectIndexedItems(indexedItems); + } } public static class DexParameterAnnotation extends @@ -65,5 +68,10 @@ public DexParameterAnnotation(DexMethod item, ParameterAnnotationsList annotations) { super(item, annotations); } + + public void collectIndexedItems(IndexedItemCollection indexedItems) { + item.collectIndexedItems(indexedItems); + annotations.collectIndexedItems(indexedItems); + } } }
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 fce08d8..999f261 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 DexTypeList getParameters() { + return proto.parameters; + } + public DexType getReturnType() { return proto.returnType; } @@ -92,26 +96,23 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - if (collectIndexedItemsExceptName(indexedItems, method, instructionOffset)) { - collectIndexedItemsName(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + if (collectIndexedItemsExceptName(indexedItems)) { + collectIndexedItemsName(indexedItems); } } - public boolean collectIndexedItemsExceptName( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { + boolean collectIndexedItemsExceptName(IndexedItemCollection indexedItems) { if (indexedItems.addMethod(this)) { - holder.collectIndexedItems(indexedItems, method, instructionOffset); - proto.collectIndexedItems(indexedItems, method, instructionOffset); + holder.collectIndexedItems(indexedItems); + proto.collectIndexedItems(indexedItems); return true; } return false; } - public void collectIndexedItemsName( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - indexedItems.getRenamedName(this).collectIndexedItems(indexedItems, method, instructionOffset); + void collectIndexedItemsName(IndexedItemCollection indexedItems) { + indexedItems.getRenamedName(this).collectIndexedItems(indexedItems); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java index 6c37bc9..80a3cb9 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -187,7 +187,7 @@ public final MethodHandleType type; // Field or method that the method handle is targeting. - public final DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod; + public final DexMember<? extends DexItem, ? extends DexMember<?, ?>> member; public final boolean isInterface; @@ -204,18 +204,18 @@ public DexMethodHandle( MethodHandleType type, - DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod, + DexMember<? extends DexItem, ? extends DexMember<?, ?>> member, boolean isInterface) { - this(type, fieldOrMethod, isInterface, null); + this(type, member, isInterface, null); } public DexMethodHandle( MethodHandleType type, - DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod, + DexMember<? extends DexItem, ? extends DexMember<?, ?>> member, boolean isInterface, DexMethod rewrittenTarget) { this.type = type; - this.fieldOrMethod = fieldOrMethod; + this.member = member; this.isInterface = isInterface; this.rewrittenTarget = rewrittenTarget; } @@ -232,7 +232,7 @@ @Override public int computeHashCode() { - return Objects.hash(type, fieldOrMethod.computeHashCode(), isInterface, rewrittenTarget); + return Objects.hash(type, member.computeHashCode(), isInterface, rewrittenTarget); } @Override @@ -240,7 +240,7 @@ if (other instanceof DexMethodHandle) { DexMethodHandle o = (DexMethodHandle) other; return type.equals(o.type) - && fieldOrMethod.equals(o.fieldOrMethod) + && member.equals(o.member) && (isInterface == o.isInterface) && Objects.equals(rewrittenTarget, o.rewrittenTarget); } @@ -249,28 +249,32 @@ @Override public String toString() { - StringBuilder builder = new StringBuilder("MethodHandle: {") + StringBuilder builder = + new StringBuilder("MethodHandle: {") .append(type) .append(", ") - .append(fieldOrMethod.toSourceString()) + .append(member.toSourceString()) .append("}"); return builder.toString(); } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { if (indexedItems.addMethodHandle(this)) { - if (fieldOrMethod.isDexMethod() && rewrittenTarget != null) { - // If there is a rewritten target we need to use that to get the right name of the - // targeted method (only member rebound methods take part in naming). The rest of the - // indexed items are collected from fieldOrMethod. - if (fieldOrMethod.asDexMethod().collectIndexedItemsExceptName( - indexedItems, method, instructionOffset)) { - rewrittenTarget.collectIndexedItemsName(indexedItems, method, instructionOffset); - } + if (member.isDexField()) { + DexField field = member.asDexField(); + field.collectIndexedItems(indexedItems); } else { - fieldOrMethod.collectIndexedItems(indexedItems, method, instructionOffset); + DexMethod method = member.asDexMethod(); + if (rewrittenTarget != null) { + // If there is a rewritten target we need to use that to get the right name of the + // targeted method (only member rebound methods take part in naming). The rest of the + // indexed items are collected from method. + if (method.collectIndexedItemsExceptName(indexedItems)) { + rewrittenTarget.collectIndexedItemsName(indexedItems); + } + } else { + method.collectIndexedItems(indexedItems); + } } } } @@ -300,12 +304,12 @@ public DexMethod asMethod() { assert isMethodHandle(); - return (DexMethod) fieldOrMethod; + return (DexMethod) member; } public DexField asField() { assert isFieldHandle(); - return (DexField) fieldOrMethod; + return (DexField) member; } @Override
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 0a5014a..90c37ed 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -221,6 +221,10 @@ : TraversalContinuation.CONTINUE); } + public Kind getOriginKind() { + return originKind; + } + public boolean originatesFromDexResource() { return originKind == Kind.DEX; } @@ -229,22 +233,20 @@ return originKind == Kind.CF; } - @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { if (indexedItems.addClass(this)) { - type.collectIndexedItems(indexedItems, method, instructionOffset); + type.collectIndexedItems(indexedItems); if (superType != null) { - superType.collectIndexedItems(indexedItems, method, instructionOffset); + superType.collectIndexedItems(indexedItems); } else { assert type.toDescriptorString().equals("Ljava/lang/Object;"); } if (sourceFile != null) { - sourceFile.collectIndexedItems(indexedItems, method, instructionOffset); + sourceFile.collectIndexedItems(indexedItems); } - annotations().collectIndexedItems(indexedItems, method, instructionOffset); + annotations().collectIndexedItems(indexedItems); if (interfaces != null) { - interfaces.collectIndexedItems(indexedItems, method, instructionOffset); + interfaces.collectIndexedItems(indexedItems); } if (getEnclosingMethodAttribute() != null) { getEnclosingMethodAttribute().collectIndexedItems(indexedItems); @@ -252,18 +254,8 @@ for (InnerClassAttribute attribute : getInnerClasses()) { attribute.collectIndexedItems(indexedItems); } - synchronizedCollectAll(indexedItems, staticFields); - synchronizedCollectAll(indexedItems, instanceFields); - synchronized (methodCollection) { - methodCollection.forEachMethod(m -> m.collectIndexedItems(indexedItems)); - } - } - } - - private static <T extends DexItem> void synchronizedCollectAll( - IndexedItemCollection collection, T[] items) { - synchronized (items) { - collectAll(collection, items); + forEachField(field -> field.collectIndexedItems(indexedItems)); + forEachMethod(method -> method.collectIndexedItems(indexedItems)); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java index a9a15f3..77b9c42 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProto.java +++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -47,13 +47,11 @@ return "Proto " + shorty + " " + returnType + " " + parameters; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { if (indexedItems.addProto(this)) { - shorty.collectIndexedItems(indexedItems, method, instructionOffset); - returnType.collectIndexedItems(indexedItems, method, instructionOffset); - parameters.collectIndexedItems(indexedItems, method, instructionOffset); + shorty.collectIndexedItems(indexedItems); + returnType.collectIndexedItems(indexedItems); + parameters.collectIndexedItems(indexedItems); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java index c37c9de..b296b43 100644 --- a/src/main/java/com/android/tools/r8/graph/DexReference.java +++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -3,11 +3,10 @@ // 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 java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Stream; /** * A common interface for {@link DexType}, {@link DexField}, and {@link DexMethod}. @@ -30,6 +29,8 @@ BiConsumer<DexMethod, T> methodConsumer, T arg); + public abstract void collectIndexedItems(IndexedItemCollection indexedItems); + public boolean isDexType() { return false; } @@ -61,27 +62,4 @@ public DexMethod asDexMethod() { return null; } - - public static Stream<DexReference> filterDexReference(Stream<DexItem> stream) { - return DexItem.filter(stream, DexReference.class); - } - - private static <T extends DexReference> Stream<T> filter( - Stream<DexReference> stream, - Predicate<DexReference> pred, - Function<DexReference, T> f) { - return stream.filter(pred).map(f); - } - - public static Stream<DexType> filterDexType(Stream<DexReference> stream) { - return filter(stream, DexReference::isDexType, DexReference::asDexType); - } - - public static Stream<DexField> filterDexField(Stream<DexReference> stream) { - return filter(stream, DexReference::isDexField, DexReference::asDexField); - } - - public static Stream<DexMethod> filterDexMethod(Stream<DexReference> stream) { - return filter(stream, DexReference::isDexMethod, DexReference::asDexMethod); - } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java index 03303f6..602a6b7 100644 --- a/src/main/java/com/android/tools/r8/graph/DexString.java +++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -239,9 +239,7 @@ return offset; } - @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection indexedItems) { indexedItems.addString(this); }
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 1190570..81c4dc5 100644 --- a/src/main/java/com/android/tools/r8/graph/DexType.java +++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -171,12 +171,9 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection collection, DexMethod method, int instructionOffset) { + public void collectIndexedItems(IndexedItemCollection collection) { if (collection.addType(this)) { - collection - .getRenamedDescriptor(this) - .collectIndexedItems(collection, method, instructionOffset); + collection.getRenamedDescriptor(this).collectIndexedItems(collection); } } @@ -387,6 +384,19 @@ return newBase.toArrayType(getNumberOfLeadingSquareBrackets(), dexItemFactory); } + public DexType replacePackage(String newPackageDescriptor, DexItemFactory dexItemFactory) { + assert isClassType(); + String descriptorString = toDescriptorString(); + int lastPackageSeparator = descriptorString.lastIndexOf('/'); + String newDescriptorString = "L" + newPackageDescriptor + "/"; + if (lastPackageSeparator >= 0) { + newDescriptorString += descriptorString.substring(lastPackageSeparator + 1); + } else { + newDescriptorString += descriptorString.substring(1); + } + return dexItemFactory.createType(newDescriptorString); + } + public DexType toArrayType(int dimensions, DexItemFactory dexItemFactory) { byte[] content = new byte[descriptor.content.length + dimensions]; Arrays.fill(content, 0, dimensions, (byte) '[');
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java index 2272c98..c61de91 100644 --- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java +++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.ArrayUtils; import java.util.Arrays; +import java.util.stream.Stream; public class DexTypeList extends DexItem { @@ -38,11 +39,9 @@ return Arrays.hashCode(values); } - @Override - void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { + void collectIndexedItems(IndexedItemCollection indexedItems) { for (DexType type : values) { - type.collectIndexedItems(indexedItems, method, instructionOffset); + type.collectIndexedItems(indexedItems); } } @@ -68,6 +67,10 @@ return values.length; } + public Stream<DexType> stream() { + return Stream.of(values); + } + @Override public String toString() { StringBuilder builder = new StringBuilder();
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java index 96b6b5a..2fe8c3f 100644 --- a/src/main/java/com/android/tools/r8/graph/DexValue.java +++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -307,6 +307,10 @@ dest.putByte((byte) ((arg << 5) | kind.toByte())); } + public void collectIndexedItems(IndexedItemCollection indexedItems) { + // Intentionally left empty + } + @Override void collectMixedSectionItems(MixedSectionCollection mixedItems) { // Should never be visited. @@ -380,12 +384,6 @@ private abstract static class SimpleDexValue extends DexValue { @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - // Intentionally left empty - } - - @Override public void sort() { // Intentionally empty } @@ -1054,12 +1052,6 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); - } - - @Override public void sort() { // Intentionally empty. } @@ -1094,6 +1086,11 @@ } @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); + } + + @Override public DexValueString asDexValueString() { return this; } @@ -1152,6 +1149,11 @@ this.nameComputationInfo = nameComputationInfo; } + @Override + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); + } + public NameComputationInfo<?> getNameComputationInfo() { return nameComputationInfo; } @@ -1223,9 +1225,8 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override @@ -1256,9 +1257,8 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override @@ -1289,9 +1289,8 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override @@ -1322,9 +1321,8 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override @@ -1365,9 +1363,8 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override @@ -1394,9 +1391,10 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - collectAll(indexedItems, values); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + for (DexValue value : values) { + value.collectIndexedItems(indexedItems); + } } @Override @@ -1492,9 +1490,8 @@ } @Override - public void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override @@ -1736,9 +1733,8 @@ } @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - value.collectIndexedItems(indexedItems, method, instructionOffset); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + value.collectIndexedItems(indexedItems); } @Override
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 edce8d8..2491193 100644 --- a/src/main/java/com/android/tools/r8/graph/GraphLens.java +++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.graph; 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; import com.android.tools.r8.utils.SetUtils; import com.google.common.collect.BiMap; @@ -151,6 +152,12 @@ public abstract DexField getRenamedFieldSignature(DexField originalField); + public final DexMember<?, ?> getRenamedMemberSignature(DexMember<?, ?> originalMember) { + return originalMember.isDexField() + ? getRenamedFieldSignature(originalMember.asDexField()) + : getRenamedMethodSignature(originalMember.asDexMethod()); + } + public final DexMethod getRenamedMethodSignature(DexMethod originalMethod) { return getRenamedMethodSignature(originalMethod, null); } @@ -250,6 +257,22 @@ return this == getIdentityLens(); } + public boolean isInterfaceProcessorLens() { + return false; + } + + public InterfaceProcessorNestedGraphLens asInterfaceProcessorLens() { + return null; + } + + public boolean isGraphLensWithPrevious() { + return false; + } + + public GraphLensWithPrevious asGraphLensWithPrevious() { + return null; + } + public GraphLens withCodeRewritingsApplied() { if (hasCodeRewritings()) { return new ClearCodeRewritingGraphLens(this); @@ -471,7 +494,8 @@ // This lens clears all code rewriting (lookup methods mimics identity lens behavior) but still // relies on the previous lens for names (getRenamed/Original methods). - public static class ClearCodeRewritingGraphLens extends IdentityGraphLens { + public static class ClearCodeRewritingGraphLens extends IdentityGraphLens + implements GraphLensWithPrevious { private final GraphLens previous; @@ -480,6 +504,21 @@ } @Override + public boolean isGraphLensWithPrevious() { + return true; + } + + @Override + public GraphLensWithPrevious asGraphLensWithPrevious() { + return this; + } + + @Override + public GraphLens getPrevious() { + return previous; + } + + @Override public DexType getOriginalType(DexType type) { return previous.getOriginalType(type); } @@ -512,6 +551,11 @@ } } + public interface GraphLensWithPrevious { + + GraphLens getPrevious(); + } + /** * GraphLens implementation with a parent lens using a simple mapping for type, method and field * mapping. @@ -522,7 +566,7 @@ * #mapInvocationType(DexMethod, DexMethod, Type)} if the default name mapping applies, and only * invocation type might need to change. */ - public static class NestedGraphLens extends GraphLens { + public static class NestedGraphLens extends GraphLens implements GraphLensWithPrevious { protected GraphLens previousLens; protected final DexItemFactory dexItemFactory; @@ -535,7 +579,7 @@ // Maps that store the original signature of fields and methods that have been affected, for // example, by vertical class merging. Needed to generate a correct Proguard map in the end. protected final BiMap<DexField, DexField> originalFieldSignatures; - protected final BiMap<DexMethod, DexMethod> originalMethodSignatures; + protected BiMap<DexMethod, DexMethod> originalMethodSignatures; // Overrides this if the sub type needs to be a nested lens while it doesn't have any mappings // at all, e.g., publicizer lens that changes invocation type only. @@ -564,6 +608,11 @@ this.dexItemFactory = dexItemFactory; } + @Override + public GraphLens getPrevious() { + return previousLens; + } + public <T> T withAlternativeParentLens(GraphLens lens, Supplier<T> action) { GraphLens oldParent = previousLens; previousLens = lens; @@ -573,6 +622,16 @@ } @Override + public boolean isGraphLensWithPrevious() { + return true; + } + + @Override + public NestedGraphLens asGraphLensWithPrevious() { + return this; + } + + @Override public DexType getOriginalType(DexType type) { return previousLens.getOriginalType(type); }
diff --git a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java index 0c115e1..96bfb47 100644 --- a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java +++ b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
@@ -3,17 +3,12 @@ // 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.dex.MixedSectionCollection; /** Subset of dex items that are referenced by some table index. */ public abstract class IndexedDexItem extends CachedHashValueDexItem { @Override - public abstract void collectIndexedItems(IndexedItemCollection indexedItems, - DexMethod method, int instructionOffset); - - @Override void collectMixedSectionItems(MixedSectionCollection mixedItems) { // Should never be visited. assert false;
diff --git a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java index 6ff5c75..4b21c2b 100644 --- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java +++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -82,10 +82,10 @@ return false; } - @Override - public void collectIndexedItems( - IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { - collectAll(indexedItems, values); + public void collectIndexedItems(IndexedItemCollection indexedItems) { + for (DexAnnotationSet value : values) { + value.collectIndexedItems(indexedItems); + } } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramPackage.java b/src/main/java/com/android/tools/r8/graph/ProgramPackage.java index 28fc4e2..c244576 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramPackage.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramPackage.java
@@ -23,6 +23,14 @@ classes.add(clazz); } + public String getLastPackageName() { + int index = packageDescriptor.lastIndexOf('/'); + if (index >= 0) { + return packageDescriptor.substring(index + 1); + } + return packageDescriptor; + } + public void forEachClass(Consumer<DexProgramClass> consumer) { forEach(consumer); }
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 e9aa061..51ef31e 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,15 +4,24 @@ package com.android.tools.r8.horizontalclassmerging; +import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexAnnotationSet; +import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; +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.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.Collection; import java.util.IdentityHashMap; import java.util.Map; @@ -28,24 +37,34 @@ private final Collection<DexProgramClass> toMergeGroup; private final DexItemFactory dexItemFactory; private final HorizontalClassMergerGraphLens.Builder lensBuilder; + private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder; + private final Reference2IntMap<DexType> classIdentifiers = new Reference2IntOpenHashMap<>(); private final Map<DexProto, ConstructorMerger.Builder> constructorMergers; + private final DexField classIdField; ClassMerger( AppView<?> appView, HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, DexProgramClass target, Collection<DexProgramClass> toMergeGroup) { this.appView = appView; this.lensBuilder = lensBuilder; + this.fieldAccessChangesBuilder = fieldAccessChangesBuilder; this.target = target; this.toMergeGroup = toMergeGroup; - this.constructorMergers = new IdentityHashMap<>(); + 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(); } - private Wrapper<DexMethod> bySignature(DexMethod method) { + Wrapper<DexMethod> bySignature(DexMethod method) { return MethodSignatureEquivalence.get().wrap(method); } @@ -56,7 +75,14 @@ .add(method); } - private void merge(DexProgramClass toMerge) { + void buildClassIdentifierMap() { + classIdentifiers.put(target.type, 0); + for (DexProgramClass toMerge : toMergeGroup) { + classIdentifiers.put(toMerge.type, classIdentifiers.size()); + } + } + + void merge(DexProgramClass toMerge) { toMerge.forEachProgramMethod( programMethod -> { DexEncodedMethod method = programMethod.getDefinition(); @@ -98,8 +124,8 @@ void mergeConstructors() { for (ConstructorMerger.Builder builder : constructorMergers.values()) { - ConstructorMerger constructorMerger = builder.build(appView, target); - constructorMerger.merge(lensBuilder); + ConstructorMerger constructorMerger = builder.build(appView, target, classIdField); + constructorMerger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers); } } @@ -117,8 +143,20 @@ }); } + void appendClassIdField() { + DexEncodedField encodedField = + new DexEncodedField( + classIdField, + FieldAccessFlags.fromSharedAccessFlags( + Constants.ACC_PUBLIC + Constants.ACC_FINAL + Constants.ACC_SYNTHETIC), + DexAnnotationSet.empty(), + null); + target.appendInstanceField(encodedField); + } + public void mergeGroup() { addTargetConstructors(); + appendClassIdField(); for (DexProgramClass clazz : toMergeGroup) { merge(clazz);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java index b182afb..ff2a898 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
@@ -4,6 +4,7 @@ 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; @@ -12,78 +13,117 @@ 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.Collection; import java.util.List; /** * Generate code of the form: <code> * MyClass(int constructorId, [args]) { * switch (constructorId) { - * case 0: - * this.Constructor$A([args]); - * return; * case 1: * this.Constructor$B([args]); * return; * ... * default: - * throw null; + * this.Constructor$A([args]); + * return; * } * } * </code> */ public class ConstructorEntryPoint extends SyntheticSourceCode { - private final Collection<DexMethod> typeConstructors; + private final DexField classIdField; + private final Int2ReferenceSortedMap<DexMethod> typeConstructors; public ConstructorEntryPoint( - Collection<DexMethod> typeConstructors, DexMethod method, Position callerPosition) { - super(method.holder, method, callerPosition); + Int2ReferenceSortedMap<DexMethod> typeConstructors, + DexMethod newConstructor, + DexField classIdField, + Position callerPosition, + DexMethod originalMethod) { + super(newConstructor.holder, newConstructor, callerPosition, originalMethod); this.typeConstructors = typeConstructors; + this.classIdField = classIdField; } - @Override - protected void prepareInstructions() { - int typeConstructorCount = typeConstructors.size(); - int idRegister = getParamRegister(0); + void addConstructorInvoke(DexMethod typeConstructor) { + add( + builder -> { + List<Value> arguments = new ArrayList<>(typeConstructor.getArity() + 1); + arguments.add(builder.getReceiverValue()); - int[] keys = new int[typeConstructorCount]; - int[] offsets = new int[typeConstructorCount]; + // If there are any arguments add them to the list. + for (int i = 0; i < typeConstructor.getArity(); i++) { + arguments.add(builder.getArgumentValues().get(i)); + } + + builder.addInvoke(Type.DIRECT, typeConstructor, typeConstructor.proto, arguments, false); + }); + } + + /** Assign the given register to the class id field. */ + void addRegisterClassIdAssignment(int idRegister) { + add(builder -> builder.addInstancePut(idRegister, getReceiverRegister(), classIdField)); + } + + /** Assign the given constant integer value to the class id field. */ + void addConstantRegisterClassIdAssignment(int classId) { + int idRegister = nextRegister(ValueType.INT); + add(builder -> builder.addIntConst(idRegister, classId)); + addRegisterClassIdAssignment(idRegister); + } + + protected void prepareMultiConstructorInstructions() { + int typeConstructorCount = typeConstructors.size(); + int idRegister = getParamRegister(method.getArity() - 1); + + addRegisterClassIdAssignment(idRegister); + + int[] keys = new int[typeConstructorCount - 1]; + int[] offsets = new int[typeConstructorCount - 1]; IntBox fallthrough = new IntBox(); int switchIndex = lastInstructionIndex(); add( builder -> builder.addSwitch(idRegister, keys, fallthrough.get(), offsets), builder -> endsSwitch(builder, switchIndex, fallthrough.get(), offsets)); - fallthrough.set(nextInstructionIndex()); - int nullRegister = nextRegister(ValueType.OBJECT); - add(builder -> builder.addNullConst(nullRegister)); - add(builder -> builder.addThrow(nullRegister), endsBlock); - int index = 0; - for (DexMethod typeConstructor : typeConstructors) { - keys[index] = index; - offsets[index] = nextInstructionIndex(); + for (Entry<DexMethod> entry : typeConstructors.int2ReferenceEntrySet()) { + int classId = entry.getIntKey(); + DexMethod typeConstructor = entry.getValue(); - add( - builder -> { - List<Value> arguments = new ArrayList<>(typeConstructor.getArity()); - arguments.add(builder.getReceiverValue()); - int paramIndex = 0; - for (Value argument : builder.getArgumentValues()) { - if (paramIndex++ >= typeConstructor.getArity()) { - break; - } - arguments.add(argument); - } - builder.addInvoke( - Type.DIRECT, typeConstructor, typeConstructor.proto, arguments, false); - }); + if (index == 0) { + // The first constructor is the fallthrough case. + fallthrough.set(nextInstructionIndex()); + } else { + // All subsequent constructors are matched on a specific case. + keys[index - 1] = classId; + offsets[index - 1] = nextInstructionIndex(); + } + addConstructorInvoke(typeConstructor); add(IRBuilder::addReturn, endsBlock); index++; } } + + protected void prepareSingleConstructorInstructions() { + Entry<DexMethod> entry = typeConstructors.int2ReferenceEntrySet().first(); + addConstantRegisterClassIdAssignment(entry.getIntKey()); + addConstructorInvoke(entry.getValue()); + add(IRBuilder::addReturn, endsBlock); + } + + @Override + protected void prepareInstructions() { + if (typeConstructors.size() > 1) { + prepareMultiConstructorInstructions(); + } else { + prepareSingleConstructorInstructions(); + } + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java new file mode 100644 index 0000000..7d250bb --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java
@@ -0,0 +1,48 @@ +// 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.AbstractSynthesizedCode; +import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap; +import java.util.function.Consumer; + +public class ConstructorEntryPointSynthesizedCode extends AbstractSynthesizedCode { + private final DexMethod newConstructor; + private final DexMethod originalMethod; + private final DexField classIdField; + private final Int2ReferenceSortedMap<DexMethod> typeConstructors; + + public ConstructorEntryPointSynthesizedCode( + Int2ReferenceSortedMap<DexMethod> typeConstructors, + DexMethod newConstructor, + DexField classIdField, + DexMethod originalMethod) { + this.typeConstructors = typeConstructors; + this.newConstructor = newConstructor; + this.classIdField = classIdField; + this.originalMethod = originalMethod; + } + + @Override + public SourceCodeProvider getSourceCodeProvider() { + return callerPosition -> + new ConstructorEntryPoint( + typeConstructors, newConstructor, classIdField, callerPosition, originalMethod); + } + + @Override + public Consumer<UseRegistry> getRegistryCallback() { + return this::registerReachableDefinitions; + } + + private void registerReachableDefinitions(UseRegistry registry) { + for (DexMethod typeConstructor : typeConstructors.values()) { + registry.registerInvokeDirect(typeConstructor); + } + } +}
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 aae7b0e..76f4814 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
@@ -8,6 +8,7 @@ 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; @@ -15,25 +16,31 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; -import com.android.tools.r8.ir.synthetic.SynthesizedCode; +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; import java.util.Collections; -import java.util.IdentityHashMap; import java.util.List; -import java.util.Map; public class ConstructorMerger { private final AppView<?> appView; private final DexProgramClass target; private final Collection<DexEncodedMethod> constructors; private final DexItemFactory dexItemFactory; + private final DexField classIdField; ConstructorMerger( - AppView<?> appView, DexProgramClass target, Collection<DexEncodedMethod> constructors) { + AppView<?> appView, + DexProgramClass target, + Collection<DexEncodedMethod> constructors, + DexField classIdField) { this.appView = appView; this.target = target; this.constructors = constructors; + this.classIdField = classIdField; // Constructors should not be empty and all constructors should have the same prototype. assert !constructors.isEmpty(); @@ -54,11 +61,16 @@ return this; } - public ConstructorMerger build(AppView<?> appView, DexProgramClass target) { - return new ConstructorMerger(appView, target, constructors); + public ConstructorMerger build( + AppView<?> appView, DexProgramClass target, DexField classIdField) { + return new ConstructorMerger(appView, target, constructors, classIdField); } } + private boolean isTrivialMerge() { + return constructors.size() == 1; + } + private DexMethod moveConstructor(DexEncodedMethod constructor) { DexMethod method = dexItemFactory.createFreshMethodName( @@ -72,7 +84,9 @@ target.removeMethod(constructor.toReference()); } - target.addDirectMethod(constructor.toTypeSubstitutedMethod(method)); + DexEncodedMethod encodedMethod = constructor.toTypeSubstitutedMethod(method); + encodedMethod.getMutableOptimizationInfo().markForceInline(); + target.addDirectMethod(encodedMethod); return method; } @@ -80,6 +94,10 @@ DexEncodedMethod firstConstructor = constructors.stream().findFirst().get(); DexProto oldProto = firstConstructor.getProto(); + if (isTrivialMerge()) { + return oldProto; + } + List<DexType> parameters = new ArrayList<>(); Collections.addAll(parameters, oldProto.parameters.values); parameters.add(dexItemFactory.intType); @@ -93,64 +111,63 @@ } /** Synthesize a new method which selects the constructor based on a parameter type. */ - void mergeMany(HorizontalClassMergerGraphLens.Builder lensBuilder) { - Map<DexType, DexMethod> typeConstructors = new IdentityHashMap<>(); + void merge( + HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, + Reference2IntMap<DexType> classIdentifiers) { + // Tree map as must be sorted. + Int2ReferenceSortedMap<DexMethod> typeConstructorClassMap = new Int2ReferenceAVLTreeMap<>(); + int classFileVersion = -1; for (DexEncodedMethod constructor : constructors) { - typeConstructors.put(constructor.holder(), moveConstructor(constructor)); + if (constructor.hasClassFileVersion()) { + classFileVersion = Integer.max(classFileVersion, constructor.getClassFileVersion()); + } + DexMethod movedConstructor = moveConstructor(constructor); + lensBuilder.recordOriginalSignature(constructor.method, movedConstructor); + typeConstructorClassMap.put( + classIdentifiers.getInt(constructor.getHolderType()), movedConstructor); } DexProto newProto = getNewConstructorProto(); - DexMethod newConstructor = + DexMethod originalConstructorReference = constructors.iterator().next().method; + DexMethod newConstructorReference = appView.dexItemFactory().createMethod(target.type, newProto, dexItemFactory.initMethodName); - SynthesizedCode synthesizedCode = - new SynthesizedCode( - callerPosition -> - new ConstructorEntryPoint( - typeConstructors.values(), newConstructor, callerPosition)); - DexEncodedMethod newMethod = + ConstructorEntryPointSynthesizedCode synthesizedCode = + new ConstructorEntryPointSynthesizedCode( + typeConstructorClassMap, + newConstructorReference, + classIdField, + originalConstructorReference); + DexEncodedMethod newConstructor = new DexEncodedMethod( - newConstructor, + newConstructorReference, getAccessFlags(), DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), - synthesizedCode); + synthesizedCode, + classFileVersion, + true); - // Map each old constructor to the newly synthesized constructor in the graph lens. - int constructorId = 0; - for (DexEncodedMethod constructor : constructors) { - lensBuilder.mapConstructor(constructor.method, newMethod.method, constructorId++); - } - - target.addDirectMethod(newMethod); - } - - /** - * The constructor does not conflict with any other constructors. Add the constructor (if any) to - * the target directly. - */ - void mergeTrivial(HorizontalClassMergerGraphLens.Builder lensBuilder) { - assert constructors.size() <= 1; - - if (!constructors.isEmpty()) { - DexEncodedMethod constructor = constructors.iterator().next(); - - // Only move the constructor if it is not already in the target type. - if (constructor.holder() != target.type) { - DexEncodedMethod newConstructor = - constructor.toRenamedHolderMethod(target.type, dexItemFactory); - target.addDirectMethod(constructor); - lensBuilder.moveConstructor(constructor.method, newConstructor.method); + if (isTrivialMerge()) { + // The constructor does not require the additional argument, just map it like a regular + // method. + lensBuilder.mapMethod(constructors.iterator().next().method, newConstructorReference); + } else { + // Map each old constructor to the newly synthesized constructor in the graph lens. + for (DexEncodedMethod oldConstructor : constructors) { + lensBuilder.mapMergedConstructor( + oldConstructor.method, + newConstructorReference, + classIdentifiers.getInt(oldConstructor.getHolderType())); } } - } + // Map the first constructor to the newly synthesized constructor. + lensBuilder.recordExtraOriginalSignature(originalConstructorReference, newConstructorReference); - public void merge(HorizontalClassMergerGraphLens.Builder lensBuilder) { - if (constructors.size() <= 1) { - mergeTrivial(lensBuilder); - } else { - mergeMany(lensBuilder); - } + target.addDirectMethod(newConstructor); + + fieldAccessChangesBuilder.fieldWrittenByMethod(classIdField, newConstructorReference); } }
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 60949e5..f7ac858 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -10,11 +10,13 @@ import com.android.tools.r8.horizontalclassmerging.policies.NoFields; import com.android.tools.r8.horizontalclassmerging.policies.NoInterfaces; import com.android.tools.r8.horizontalclassmerging.policies.NoInternalUtilityClasses; -import com.android.tools.r8.horizontalclassmerging.policies.NoOverlappingConstructors; +import com.android.tools.r8.horizontalclassmerging.policies.NoRuntimeTypeChecks; import com.android.tools.r8.horizontalclassmerging.policies.NoStaticClassInitializer; import com.android.tools.r8.horizontalclassmerging.policies.NotEntryPoint; import com.android.tools.r8.horizontalclassmerging.policies.SameParentClass; 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.google.common.collect.ImmutableList; import java.util.ArrayList; @@ -25,26 +27,25 @@ import java.util.Map; public class HorizontalClassMerger { - private final AppView<AppInfoWithLiveness> appView; - private final MainDexClasses mainDexClasses; - private final PolicyExecutor policyExecutor; public HorizontalClassMerger( - AppView<AppInfoWithLiveness> appView, MainDexClasses mainDexClasses) { + AppView<AppInfoWithLiveness> appView, + MainDexClasses mainDexClasses, + ClassMergingEnqueuerExtension classMergingEnqueuerExtension) { this.appView = appView; - this.mainDexClasses = mainDexClasses; List<Policy> policies = ImmutableList.of( new NoFields(), + // TODO(b/166071504): Allow merging of classes that implement interfaces. new NoInterfaces(), new NoStaticClassInitializer(), + new NoRuntimeTypeChecks(classMergingEnqueuerExtension), new NotEntryPoint(appView.dexItemFactory()), new NoInternalUtilityClasses(appView.dexItemFactory()), - new SameParentClass(), - new NoOverlappingConstructors() + new SameParentClass() // TODO: add policies ); @@ -76,6 +77,8 @@ Map<DexType, DexType> mergedClasses = new IdentityHashMap<>(); HorizontalClassMergerGraphLens.Builder lensBuilder = new HorizontalClassMergerGraphLens.Builder(); + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder = + new FieldAccessInfoCollectionModifier.Builder(); // TODO(b/166577694): Replace Collection<DexProgramClass> with MergeGroup for (Collection<DexProgramClass> group : groups) { @@ -88,12 +91,14 @@ mergedClasses.put(clazz.type, target.type); } - ClassMerger merger = new ClassMerger(appView, lensBuilder, target, group); + ClassMerger merger = + new ClassMerger(appView, lensBuilder, fieldAccessChangesBuilder, target, group); merger.mergeGroup(); } HorizontalClassMergerGraphLens lens = - new TreeFixer(appView, lensBuilder, mergedClasses).fixupTypeReferences(); + new TreeFixer(appView, lensBuilder, fieldAccessChangesBuilder, mergedClasses) + .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 451e550..4389282 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -10,6 +10,8 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.ir.code.Invoke.Type; +import com.android.tools.r8.ir.conversion.ExtraConstantIntParameter; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import java.util.Collections; @@ -20,14 +22,18 @@ public class HorizontalClassMergerGraphLens extends NestedGraphLens { private final AppView<?> appView; + private final Map<DexMethod, Integer> constructorIds; + private final Map<DexMethod, DexMethod> originalConstructorSignatures; private HorizontalClassMergerGraphLens( AppView<?> appView, + Map<DexMethod, Integer> constructorIds, Map<DexType, DexType> typeMap, Map<DexField, DexField> fieldMap, Map<DexMethod, DexMethod> methodMap, BiMap<DexField, DexField> originalFieldSignatures, BiMap<DexMethod, DexMethod> originalMethodSignatures, + Map<DexMethod, DexMethod> originalConstructorSignatures, GraphLens previousLens) { super( typeMap, @@ -38,12 +44,44 @@ previousLens, appView.dexItemFactory()); this.appView = appView; + this.constructorIds = constructorIds; + this.originalConstructorSignatures = originalConstructorSignatures; + } + + @Override + public DexMethod getOriginalMethodSignature(DexMethod method) { + DexMethod originalConstructor = originalConstructorSignatures.get(method); + if (originalConstructor == null) { + return super.getOriginalMethodSignature(method); + } + return previousLens.getOriginalMethodSignature(originalConstructor); } public HorizontallyMergedClasses getHorizontallyMergedClasses() { return new HorizontallyMergedClasses(this.typeMap); } + /** + * If an overloaded constructor is requested, add the constructor id as a parameter to the + * constructor. Otherwise return the lookup on the underlying graph lens. + */ + @Override + public GraphLensLookupResult lookupMethod(DexMethod method, DexMethod context, Type type) { + Integer constructorId = constructorIds.get(method); + GraphLensLookupResult lookup = super.lookupMethod(method, context, type); + if (constructorId != null) { + DexMethod newMethod = lookup.getMethod(); + return new GraphLensLookupResult( + newMethod, + mapInvocationType(newMethod, method, lookup.getType()), + lookup + .getPrototypeChanges() + .withExtraParameter(new ExtraConstantIntParameter(constructorId))); + } else { + return lookup; + } + } + public static class Builder { protected final BiMap<DexField, DexField> fieldMap = HashBiMap.create(); protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>(); @@ -51,6 +89,7 @@ new IdentityHashMap<>(); private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create(); + private final Map<DexMethod, DexMethod> extraOriginalMethodSignatures = new IdentityHashMap<>(); private final Map<DexMethod, Integer> constructorIds = new IdentityHashMap<>(); @@ -64,11 +103,13 @@ BiMap<DexField, DexField> originalFieldSignatures = fieldMap.inverse(); return new HorizontalClassMergerGraphLens( appView, + constructorIds, mergedClasses, fieldMap, methodMap, originalFieldSignatures, originalMethodSignatures, + extraOriginalMethodSignatures, appView.graphLens()); } } @@ -76,16 +117,23 @@ /** Bidirectional mapping from one method to another. */ public Builder moveMethod(DexMethod from, DexMethod to) { mapMethod(from, to); - originalMethodSignatures.put(to, from); + recordOriginalSignature(from, to); return this; } - /** - * Unidirectional mapping from one method to another. This seems to only be used by synthesized - * constructors so is private for now. See {@link Builder#moveConstructor(DexMethod, - * DexMethod)}. - */ - private Builder mapMethod(DexMethod from, DexMethod to) { + public Builder recordOriginalSignature(DexMethod from, DexMethod to) { + originalMethodSignatures.forcePut(to, originalMethodSignatures.getOrDefault(from, from)); + return this; + } + + /** Unidirectional mapping from one method to another. */ + public Builder recordExtraOriginalSignature(DexMethod from, DexMethod to) { + extraOriginalMethodSignatures.put(to, extraOriginalMethodSignatures.getOrDefault(from, from)); + return this; + } + + /** Unidirectional mapping from one method to another. */ + public Builder mapMethod(DexMethod from, DexMethod to) { for (DexMethod existingFrom : completeInverseMethodMap.getOrDefault(from, Collections.emptySet())) { methodMap.put(existingFrom, to); @@ -100,6 +148,10 @@ return this; } + public boolean hasExtraSignatureMappingFor(DexMethod method) { + return extraOriginalMethodSignatures.containsKey(method); + } + public boolean hasOriginalSignatureMappingFor(DexMethod method) { return originalMethodSignatures.containsKey(method); } @@ -112,18 +164,10 @@ * @param constructorId The id that must be appended to the constructor call to ensure the * correct constructor is called. */ - public Builder mapConstructor(DexMethod from, DexMethod to, int constructorId) { + public Builder mapMergedConstructor(DexMethod from, DexMethod to, int constructorId) { mapMethod(from, to); constructorIds.put(from, constructorId); return this; } - - /** - * Bidirectional mapping from one constructor to another. When a single constructor is simply - * moved from one class to another, we can uniquely map the new constructor back to the old one. - */ - public Builder moveConstructor(DexMethod from, DexMethod to) { - return moveMethod(from, to); - } } }
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 cd2cabf..7d0d5c0 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -15,6 +15,7 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.shaking.AnnotationFixer; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier; import com.android.tools.r8.utils.OptionalBool; import java.util.IdentityHashMap; import java.util.List; @@ -30,14 +31,17 @@ private final Map<DexType, DexType> mergedClasses; private final Map<DexProto, DexProto> protoFixupCache = new IdentityHashMap<>(); private final HorizontalClassMergerGraphLens.Builder lensBuilder; + private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder; private final AppView<AppInfoWithLiveness> appView; public TreeFixer( AppView<AppInfoWithLiveness> appView, HorizontalClassMergerGraphLens.Builder lensBuilder, + FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder, Map<DexType, DexType> mergedClasses) { this.mergedClasses = mergedClasses; this.lensBuilder = lensBuilder; + this.fieldAccessChangesBuilder = fieldAccessChangesBuilder; this.appView = appView; } @@ -50,6 +54,8 @@ } HorizontalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses); + fieldAccessChangesBuilder.build(this::fixupMethod).modify(appView); + if (lens != null) { new AnnotationFixer(lens).run(appView.appInfo().classes()); } @@ -63,7 +69,15 @@ return method; } - lensBuilder.moveMethod(methodReference, newMethodReference); + // If the method is a synthesized method, then don't record the original signature. + if ((method.getCode() instanceof ConstructorEntryPointSynthesizedCode)) { + assert lensBuilder.hasExtraSignatureMappingFor(methodReference); + lensBuilder.recordExtraOriginalSignature(methodReference, newMethodReference); + lensBuilder.mapMethod(methodReference, newMethodReference); + } else { + lensBuilder.moveMethod(methodReference, newMethodReference); + } + DexEncodedMethod newMethod = method.toTypeSubstitutedMethod(newMethodReference); if (newMethod.isNonPrivateVirtualMethod()) { // Since we changed the return type or one of the parameters, this method cannot be a
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoRuntimeTypeChecks.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoRuntimeTypeChecks.java new file mode 100644 index 0000000..dff9967 --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoRuntimeTypeChecks.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.horizontalclassmerging.policies; + +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy; +import com.android.tools.r8.shaking.ClassMergingEnqueuerExtension; + +public class NoRuntimeTypeChecks extends SingleClassPolicy { + private final ClassMergingEnqueuerExtension classMergingEnqueuerExtension; + + public NoRuntimeTypeChecks(ClassMergingEnqueuerExtension classMergingEnqueuerExtension) { + this.classMergingEnqueuerExtension = classMergingEnqueuerExtension; + } + + @Override + public boolean canMerge(DexProgramClass clazz) { + // We currently assume we only merge classes that implement the same set of interfaces. + return !(this.classMergingEnqueuerExtension.isCheckCastType(clazz) + || this.classMergingEnqueuerExtension.isInstanceOfType(clazz)); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java index 7dc7daa..3f40cba 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -274,7 +274,7 @@ // the 'addForward' call-back is called with the target of the forward. private void resolveForwardForSignature( DexClass clazz, DexMethod method, BiConsumer<DexClass, DexEncodedMethod> addForward) { - // Resolve the default method at base type as the symbolic holder at call sites is not known. + // Resolve the default method with base type as the symbolic holder as call sites are not known. // The dispatch target is then looked up from the possible "instance" class. // Doing so can cause an invalid invoke to become valid (at runtime resolution at a subtype // might have failed which is hidden by the insertion of the forward method). However, not doing @@ -298,7 +298,7 @@ DexEncodedMethod target = virtualDispatchTarget.getDefinition(); DexClass targetHolder = virtualDispatchTarget.getHolder(); - // Don-t forward if the target is explicitly marked as 'dont-rewrite' + // Don't forward if the target is explicitly marked as 'dont-rewrite' if (dontRewrite(targetHolder, target)) { return; }
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 2167964..6f46dc6 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
@@ -26,7 +26,6 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.DexTypeList; import com.android.tools.r8.graph.DexValue; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.BasicBlock; import com.android.tools.r8.ir.code.IRCode; @@ -1032,7 +1031,8 @@ } private Map<DexType, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) { - NestedGraphLens.Builder graphLensBuilder = InterfaceProcessorNestedGraphLens.builder(); + InterfaceProcessorNestedGraphLens.Builder graphLensBuilder = + InterfaceProcessorNestedGraphLens.builder(); InterfaceProcessor processor = new InterfaceProcessor(appView, this); for (DexProgramClass clazz : builder.getProgramClasses()) { if (shouldProcess(clazz, flavour, true)) { @@ -1215,21 +1215,29 @@ } public static void reportDependencyEdge( - DexProgramClass dependent, DexClass dependency, InternalOptions options) { + DexClass dependent, DexClass dependency, InternalOptions options) { + assert !dependent.isLibraryClass(); assert !dependency.isLibraryClass(); DesugarGraphConsumer consumer = options.desugarGraphConsumer; if (consumer != null) { Origin dependencyOrigin = dependency.getOrigin(); - java.util.Collection<DexProgramClass> dependents = dependent.getSynthesizedFrom(); + java.util.Collection<DexProgramClass> dependents = + dependent.isProgramClass() ? dependent.asProgramClass().getSynthesizedFrom() : null; if (dependents == null || dependents.isEmpty()) { - dependents = Collections.singletonList(dependent); - } - for (DexProgramClass clazz : dependents) { - Origin dependentOrigin = clazz.getOrigin(); - if (dependentOrigin != dependencyOrigin) { - consumer.accept(dependentOrigin, dependencyOrigin); + reportDependencyEdge(consumer, dependencyOrigin, dependent); + } else { + for (DexClass clazz : dependents) { + reportDependencyEdge(consumer, dependencyOrigin, clazz); } } } } + + private static void reportDependencyEdge( + DesugarGraphConsumer consumer, Origin dependencyOrigin, DexClass clazz) { + Origin dependentOrigin = clazz.getOrigin(); + if (dependentOrigin != dependencyOrigin) { + consumer.accept(dependentOrigin, dependencyOrigin); + } + } }
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 f400369..6864127 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
@@ -36,6 +36,7 @@ import com.android.tools.r8.origin.SynthesizedOrigin; import com.android.tools.r8.utils.Pair; import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -52,7 +53,7 @@ // a companion class. Removes bridge default methods. // // Also moves static interface methods into a companion class. -final class InterfaceProcessor { +public final class InterfaceProcessor { private final AppView<?> appView; private final InterfaceMethodRewriter rewriter; @@ -66,7 +67,7 @@ this.rewriter = rewriter; } - void process(DexProgramClass iface, NestedGraphLens.Builder graphLensBuilder) { + void process(DexProgramClass iface, InterfaceProcessorNestedGraphLens.Builder graphLensBuilder) { assert iface.isInterface(); // The list of methods to be created in companion class. List<DexEncodedMethod> companionMethods = new ArrayList<>(); @@ -105,7 +106,7 @@ implMethod.copyMetadata(virtual); virtual.setDefaultInterfaceMethodImplementation(implMethod); companionMethods.add(implMethod); - graphLensBuilder.move(virtual.method, implMethod.method); + graphLensBuilder.recordOrigin(implMethod.method, virtual.method); } // Remove bridge methods. @@ -385,12 +386,15 @@ // are to static companion methods. public static class InterfaceProcessorNestedGraphLens extends NestedGraphLens { + private BiMap<DexMethod, DexMethod> extraOriginalMethodSignatures; + public InterfaceProcessorNestedGraphLens( Map<DexType, DexType> typeMap, Map<DexMethod, DexMethod> methodMap, Map<DexField, DexField> fieldMap, BiMap<DexField, DexField> originalFieldSignatures, BiMap<DexMethod, DexMethod> originalMethodSignatures, + BiMap<DexMethod, DexMethod> extraOriginalMethodSignatures, GraphLens previousLens, DexItemFactory dexItemFactory) { super( @@ -401,6 +405,54 @@ originalMethodSignatures, previousLens, dexItemFactory); + this.extraOriginalMethodSignatures = extraOriginalMethodSignatures; + } + + public static InterfaceProcessorNestedGraphLens find(GraphLens lens) { + if (lens.isInterfaceProcessorLens()) { + return lens.asInterfaceProcessorLens(); + } + if (lens.isIdentityLens()) { + return null; + } + if (lens.isGraphLensWithPrevious()) { + return find(lens.asGraphLensWithPrevious().getPrevious()); + } + assert false; + return null; + } + + public void toggleMappingToExtraMethods() { + BiMap<DexMethod, DexMethod> tmp = originalMethodSignatures; + this.originalMethodSignatures = extraOriginalMethodSignatures; + this.extraOriginalMethodSignatures = tmp; + } + + @Override + public boolean isInterfaceProcessorLens() { + return true; + } + + @Override + public InterfaceProcessorNestedGraphLens asInterfaceProcessorLens() { + return this; + } + + @Override + public boolean isLegitimateToHaveEmptyMappings() { + return true; + } + + @Override + public DexMethod getOriginalMethodSignature(DexMethod method) { + DexMethod originalMethod = extraOriginalMethodSignatures.get(method); + if (originalMethod == null) { + originalMethod = + originalMethodSignatures != null + ? originalMethodSignatures.getOrDefault(method, method) + : method; + } + return previousLens.getOriginalMethodSignature(originalMethod); } @Override @@ -408,14 +460,26 @@ return Type.STATIC; } - public static GraphLens.Builder builder() { + public static Builder builder() { return new Builder(); } public static class Builder extends NestedGraphLens.Builder { + + private final BiMap<DexMethod, DexMethod> extraOriginalMethodSignatures = HashBiMap.create(); + + public void recordOrigin(DexMethod method, DexMethod origin) { + if (method == origin) { + return; + } + extraOriginalMethodSignatures.put(method, origin); + } + @Override public GraphLens build(DexItemFactory dexItemFactory, GraphLens previousLens) { - if (originalFieldSignatures.isEmpty() && originalMethodSignatures.isEmpty()) { + if (originalFieldSignatures.isEmpty() + && originalMethodSignatures.isEmpty() + && extraOriginalMethodSignatures.isEmpty()) { return previousLens; } return new InterfaceProcessorNestedGraphLens( @@ -424,6 +488,7 @@ fieldMap, originalFieldSignatures, originalMethodSignatures, + extraOriginalMethodSignatures, previousLens, dexItemFactory); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java index bc3c320..d28ee6d 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -16,6 +16,8 @@ import com.android.tools.r8.cf.code.CfCmp; import com.android.tools.r8.cf.code.CfConstNumber; import com.android.tools.r8.cf.code.CfConstString; +import com.android.tools.r8.cf.code.CfFrame; +import com.android.tools.r8.cf.code.CfFrame.FrameType; import com.android.tools.r8.cf.code.CfGoto; import com.android.tools.r8.cf.code.CfIf; import com.android.tools.r8.cf.code.CfIfCmp; @@ -45,6 +47,8 @@ import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; +import java.util.Arrays; public final class BackportedMethods { @@ -52,6 +56,7 @@ factory.createSynthesizedType("Ljava/lang/ArithmeticException;"); factory.createSynthesizedType("Ljava/lang/AssertionError;"); factory.createSynthesizedType("Ljava/lang/Double;"); + factory.createSynthesizedType("Ljava/lang/Exception;"); factory.createSynthesizedType("Ljava/lang/ExceptionInInitializerError;"); factory.createSynthesizedType("Ljava/lang/Float;"); factory.createSynthesizedType("Ljava/lang/IllegalAccessException;"); @@ -97,8 +102,10 @@ factory.createSynthesizedType("Ljava/util/stream/IntStream;"); factory.createSynthesizedType("Ljava/util/stream/LongStream;"); factory.createSynthesizedType("Ljava/util/stream/Stream;"); + factory.createSynthesizedType("[Ljava/lang/CharSequence;"); factory.createSynthesizedType("[Ljava/lang/Class;"); factory.createSynthesizedType("[Ljava/lang/Object;"); + factory.createSynthesizedType("[Ljava/util/Map$Entry;"); } public static CfCode BooleanMethods_compare(InternalOptions options, DexMethod method) { @@ -119,13 +126,37 @@ new CfConstNumber(0, ValueType.INT), new CfGoto(label3), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfIf(If.Type.EQ, ValueType.INT, label2), new CfConstNumber(1, ValueType.INT), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(-1, ValueType.INT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label4), ImmutableList.of(), @@ -148,8 +179,18 @@ new CfConstNumber(1231, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList()), new CfConstNumber(1237, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -281,6 +322,16 @@ new CfConstNumber(0, ValueType.INT), new CfReturn(ValueType.INT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), new CfStore(ValueType.INT, 4), label5, @@ -298,6 +349,18 @@ false), new CfStore(ValueType.INT, 5), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4, 5}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 4), new CfLoad(ValueType.INT, 5), new CfIfCmp(If.Type.GE, ValueType.INT, label12), @@ -335,9 +398,31 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), new CfReturn(ValueType.INT), label11, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4, 5}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfIinc(4, 1), new CfGoto(label6), label12, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfLoad(ValueType.INT, 3), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), @@ -441,6 +526,14 @@ true), new CfGoto(label11), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 182, @@ -482,6 +575,16 @@ label4, new CfGoto(label11), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList( + FrameType.initialized( + options.itemFactory.createType("Ljava/lang/Exception;")))), new CfStore(ValueType.OBJECT, 2), label6, new CfNew(options.itemFactory.createType("Ljava/lang/AssertionError;")), @@ -540,6 +643,14 @@ false), new CfThrow(), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.throwableType))), new CfStore(ValueType.OBJECT, 2), label8, new CfNew(options.itemFactory.createType("Ljava/lang/AssertionError;")), @@ -598,6 +709,17 @@ false), new CfThrow(), label9, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList( + FrameType.initialized( + options.itemFactory.createType( + "Ljava/lang/reflect/InvocationTargetException;")))), new CfStore(ValueType.OBJECT, 2), label10, new CfLoad(ValueType.OBJECT, 2), @@ -610,8 +732,24 @@ false), new CfThrow(), label11, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfGoto(label16), label12, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.throwableType))), new CfStore(ValueType.OBJECT, 2), label13, new CfLoad(ValueType.OBJECT, 0), @@ -619,10 +757,36 @@ new CfLoad(ValueType.OBJECT, 0), new CfGoto(label15), label14, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.throwableType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), label15, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.throwableType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.throwableType))), new CfThrow(), label16, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.throwableType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfReturnVoid(), label17), ImmutableList.of( @@ -706,6 +870,18 @@ new CfConstNumber(0, ValueType.INT), new CfStore(ValueType.INT, 4), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/ArrayList;")), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 4), new CfLoad(ValueType.INT, 3), new CfIfCmp(If.Type.GE, ValueType.INT, label5), @@ -737,6 +913,14 @@ new CfIinc(4, 1), new CfGoto(label2), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/ArrayList;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 184, @@ -844,6 +1028,19 @@ new CfConstNumber(0, ValueType.INT), new CfStore(ValueType.INT, 4), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("[Ljava/util/Map$Entry;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashMap;")), + FrameType.initialized( + options.itemFactory.createType("[Ljava/util/Map$Entry;")), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 4), new CfLoad(ValueType.INT, 3), new CfIfCmp(If.Type.GE, ValueType.INT, label8), @@ -949,9 +1146,31 @@ false), new CfThrow(), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("[Ljava/util/Map$Entry;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashMap;")), + FrameType.initialized( + options.itemFactory.createType("[Ljava/util/Map$Entry;")), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfIinc(4, 1), new CfGoto(label2), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("[Ljava/util/Map$Entry;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashMap;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 184, @@ -1005,6 +1224,17 @@ new CfConstNumber(0, ValueType.INT), new CfStore(ValueType.INT, 4), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashSet;")), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 4), new CfLoad(ValueType.INT, 3), new CfIfCmp(If.Type.GE, ValueType.INT, label6), @@ -1079,9 +1309,28 @@ false), new CfThrow(), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashSet;")), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfIinc(4, 1), new CfGoto(label2), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashSet;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 184, @@ -1143,6 +1392,17 @@ true), new CfStore(ValueType.OBJECT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/Collection;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/ArrayList;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/Iterator;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -1184,6 +1444,15 @@ label4, new CfGoto(label2), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/Collection;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/ArrayList;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 184, @@ -1256,6 +1525,15 @@ true), new CfStore(ValueType.OBJECT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Map;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashMap;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/Iterator;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -1326,6 +1604,14 @@ label7, new CfGoto(label2), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Map;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashMap;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 184, @@ -1387,6 +1673,16 @@ true), new CfStore(ValueType.OBJECT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/Collection;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashSet;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/Iterator;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -1428,6 +1724,15 @@ label4, new CfGoto(label2), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/Collection;")), + FrameType.initialized(options.itemFactory.createType("Ljava/util/HashSet;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 184, @@ -1601,8 +1906,18 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.doubleType)}), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.doubleType)}), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -1643,8 +1958,18 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.floatType)}), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.floatType)}), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -1669,14 +1994,38 @@ new CfConstNumber(0, ValueType.INT), new CfGoto(label3), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfLoad(ValueType.INT, 1), new CfIfCmp(If.Type.GE, ValueType.INT, label2), new CfConstNumber(-1, ValueType.INT), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.INT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label4), ImmutableList.of(), @@ -1832,6 +2181,14 @@ false), new CfStore(ValueType.OBJECT, 0), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfLoad(ValueType.INT, 1), new CfInvoke( @@ -1927,6 +2284,15 @@ false), new CfThrow(), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 2), new CfNumberConversion(NumericType.LONG, NumericType.INT), new CfReturn(ValueType.INT), @@ -2134,9 +2500,27 @@ new CfConstNumber(0, ValueType.LONG), new CfReturn(ValueType.LONG), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.LONG), new CfReturn(ValueType.LONG), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(0, ValueType.LONG), new CfCmp(Cmp.Bias.NONE, NumericType.LONG), @@ -2147,6 +2531,14 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Div, NumericType.LONG), new CfReturn(ValueType.LONG), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(1, ValueType.INT), new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.LONG), @@ -2181,8 +2573,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label14), label13, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6, 8, 10}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.longType))), new CfConstNumber(0, ValueType.INT), label14, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6, 8, 10}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList( + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType))), new CfNumberConversion(NumericType.INT, NumericType.LONG), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG), new CfReturn(ValueType.LONG), @@ -2295,6 +2713,15 @@ false), new CfThrow(), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfConstNumber(2, ValueType.INT), new CfIfCmp(If.Type.LT, ValueType.INT, label4), @@ -2302,6 +2729,15 @@ new CfConstNumber(36, ValueType.INT), new CfIfCmp(If.Type.LE, ValueType.INT, label5), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/NumberFormatException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfConstString(options.itemFactory.createString("illegal radix: ")), @@ -2332,6 +2768,15 @@ false), new CfThrow(), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(-1, ValueType.LONG), new CfLoad(ValueType.INT, 1), new CfNumberConversion(NumericType.INT, NumericType.LONG), @@ -2365,8 +2810,28 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label8), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfStore(ValueType.INT, 5), label9, new CfConstNumber(0, ValueType.LONG), @@ -2375,6 +2840,19 @@ new CfLoad(ValueType.INT, 5), new CfStore(ValueType.INT, 8), label11, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 5, 6, 8}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 8), new CfLoad(ValueType.INT, 2), new CfIfCmp(If.Type.GE, ValueType.INT, label20), @@ -2419,6 +2897,20 @@ false), new CfThrow(), label15, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 5, 6, 8, 9}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 6), new CfConstNumber(0, ValueType.LONG), new CfCmp(Cmp.Bias.NONE, NumericType.LONG), @@ -2449,6 +2941,20 @@ new CfNumberConversion(NumericType.LONG, NumericType.INT), new CfIfCmp(If.Type.LE, ValueType.INT, label18), label17, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 5, 6, 8, 9}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/NumberFormatException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfConstString(options.itemFactory.createString("Too large for unsigned long: ")), @@ -2471,6 +2977,20 @@ false), new CfThrow(), label18, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 5, 6, 8, 9}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 6), new CfLoad(ValueType.INT, 1), new CfNumberConversion(NumericType.INT, NumericType.LONG), @@ -2483,6 +3003,18 @@ new CfIinc(8, 1), new CfGoto(label11), label20, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 5, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 6), new CfReturn(ValueType.LONG), label21), @@ -2536,11 +3068,29 @@ new CfLoad(ValueType.LONG, 0), new CfReturn(ValueType.LONG), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.LONG, 2), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG), new CfReturn(ValueType.LONG), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(0, ValueType.LONG), new CfCmp(Cmp.Bias.NONE, NumericType.LONG), @@ -2551,6 +3101,14 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Rem, NumericType.LONG), new CfReturn(ValueType.LONG), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(1, ValueType.INT), new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.LONG), @@ -2585,8 +3143,34 @@ new CfLoad(ValueType.LONG, 2), new CfGoto(label14), label13, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6, 8, 10}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.longType))), new CfConstNumber(0, ValueType.LONG), label14, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6, 8, 10}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList( + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType))), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG), new CfReturn(ValueType.LONG), label15), @@ -2664,6 +3248,14 @@ new CfConstString(options.itemFactory.createString("0")), new CfReturn(ValueType.OBJECT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(0, ValueType.LONG), new CfCmp(Cmp.Bias.NONE, NumericType.LONG), @@ -2683,6 +3275,14 @@ false), new CfReturn(ValueType.OBJECT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfConstNumber(2, ValueType.INT), new CfIfCmp(If.Type.LT, ValueType.INT, label5), @@ -2690,9 +3290,25 @@ new CfConstNumber(36, ValueType.INT), new CfIfCmp(If.Type.LE, ValueType.INT, label6), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(10, ValueType.INT), new CfStore(ValueType.INT, 2), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(64, ValueType.INT), new CfNewArray(options.itemFactory.charArrayType), new CfStore(ValueType.OBJECT, 3), @@ -2724,6 +3340,18 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), new CfStore(ValueType.INT, 6), label11, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 3, 4, 5, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.charArrayType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 3), new CfIinc(4, -1), new CfLoad(ValueType.INT, 4), @@ -2756,6 +3384,16 @@ label14, new CfGoto(label25), label15, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.charArrayType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfConstNumber(1, ValueType.INT), new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT), @@ -2773,6 +3411,16 @@ label17, new CfGoto(label19), label18, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.charArrayType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.INT, 2), new CfNumberConversion(NumericType.INT, NumericType.LONG), @@ -2788,6 +3436,17 @@ false), new CfStore(ValueType.LONG, 5), label19, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 3, 4, 5}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.charArrayType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.LONG, 5), new CfLoad(ValueType.INT, 2), @@ -2817,6 +3476,18 @@ new CfLoad(ValueType.LONG, 5), new CfStore(ValueType.LONG, 0), label22, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 3, 4, 5, 7}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.charArrayType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(0, ValueType.LONG), new CfCmp(Cmp.Bias.NONE, NumericType.LONG), @@ -2850,6 +3521,16 @@ new CfStore(ValueType.LONG, 0), new CfGoto(label22), label25, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.charArrayType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.stringType), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfLoad(ValueType.OBJECT, 3), @@ -2908,6 +3589,16 @@ new CfLoad(ValueType.INT, 4), new CfReturn(ValueType.INT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/ArithmeticException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -2953,8 +3644,26 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.LONG, 4), new CfLogicalBinop(CfLogicalBinop.Opcode.Xor, NumericType.LONG), @@ -2964,14 +3673,43 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label5), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfConstNumber(0, ValueType.INT), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList( + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType))), new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT), new CfIf(If.Type.EQ, ValueType.INT, label7), label6, new CfLoad(ValueType.LONG, 4), new CfReturn(ValueType.LONG), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/ArithmeticException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -3013,6 +3751,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfConstNumber(1, ValueType.INT), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), @@ -3049,6 +3792,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.longType)}), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(1, ValueType.LONG), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG), @@ -3092,6 +3840,16 @@ new CfLoad(ValueType.INT, 2), new CfReturn(ValueType.INT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.INT), new CfLoad(ValueType.INT, 0), new CfLoad(ValueType.INT, 1), @@ -3108,8 +3866,30 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), new CfGoto(label7), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label8), ImmutableList.of(), @@ -3152,6 +3932,16 @@ new CfLoad(ValueType.LONG, 4), new CfReturn(ValueType.LONG), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.LONG), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.LONG, 2), @@ -3170,8 +3960,30 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG), new CfGoto(label7), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6, 8}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 4), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6, 8}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.longType))), new CfReturn(ValueType.LONG), label8), ImmutableList.of(), @@ -3232,6 +4044,15 @@ new CfConstNumber(0, ValueType.INT), new CfReturn(ValueType.INT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.INT), new CfLoad(ValueType.INT, 0), new CfLoad(ValueType.INT, 1), @@ -3246,10 +4067,30 @@ new CfLoad(ValueType.INT, 2), new CfGoto(label6), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfLoad(ValueType.INT, 1), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label7), ImmutableList.of(), @@ -3284,6 +4125,15 @@ new CfConstNumber(0, ValueType.LONG), new CfReturn(ValueType.LONG), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.LONG), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.LONG, 2), @@ -3300,10 +4150,30 @@ new CfLoad(ValueType.LONG, 4), new CfGoto(label6), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 4), new CfLoad(ValueType.LONG, 2), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 6}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.longType))), new CfReturn(ValueType.LONG), label7), ImmutableList.of(), @@ -3365,6 +4235,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfConstNumber(1, ValueType.INT), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT), @@ -3401,6 +4276,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.longType)}), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfConstNumber(1, ValueType.LONG), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG), @@ -3443,6 +4323,16 @@ new CfLoad(ValueType.INT, 4), new CfReturn(ValueType.INT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/ArithmeticException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -3540,6 +4430,15 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG), new CfReturn(ValueType.LONG), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 4), new CfConstNumber(64, ValueType.INT), new CfIfCmp(If.Type.LT, ValueType.INT, label15), @@ -3550,8 +4449,26 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label9), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label9, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfLoad(ValueType.LONG, 2), new CfConstNumber(-9223372036854775808L, ValueType.LONG), new CfCmp(Cmp.Bias.NONE, NumericType.LONG), @@ -3559,8 +4476,28 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label11), label10, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfConstNumber(0, ValueType.INT), label11, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList( + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType))), new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT), new CfIf(If.Type.EQ, ValueType.INT, label15), label12, @@ -3580,9 +4517,28 @@ new CfCmp(Cmp.Bias.NONE, NumericType.LONG), new CfIf(If.Type.NE, ValueType.INT, label15), label14, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4, 5}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfLoad(ValueType.LONG, 5), new CfReturn(ValueType.LONG), label15, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/ArithmeticException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -3776,6 +4732,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfNeg(NumericType.INT), new CfReturn(ValueType.INT), @@ -3811,6 +4772,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.longType)}), + Arrays.asList()), new CfLoad(ValueType.LONG, 0), new CfNeg(NumericType.LONG), new CfReturn(ValueType.LONG), @@ -3904,6 +4870,16 @@ new CfLoad(ValueType.INT, 4), new CfReturn(ValueType.INT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/ArithmeticException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -3949,8 +4925,26 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfLoad(ValueType.LONG, 0), new CfLoad(ValueType.LONG, 4), new CfLogicalBinop(CfLogicalBinop.Opcode.Xor, NumericType.LONG), @@ -3960,14 +4954,43 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label5), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfConstNumber(0, ValueType.INT), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList( + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType))), new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT), new CfIf(If.Type.EQ, ValueType.INT, label7), label6, new CfLoad(ValueType.LONG, 4), new CfReturn(ValueType.LONG), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.longType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/ArithmeticException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -4016,6 +5039,14 @@ false), new CfThrow(), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.longType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfReturn(ValueType.INT), label4), @@ -4047,6 +5078,15 @@ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), new CfIfCmp(If.Type.LE, ValueType.INT, label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/IndexOutOfBoundsException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfNew(options.itemFactory.stringBuilderType), @@ -4147,6 +5187,15 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfReturn(ValueType.INT), label3), @@ -4174,6 +5223,15 @@ new CfLoad(ValueType.INT, 2), new CfIfCmp(If.Type.LE, ValueType.INT, label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/IndexOutOfBoundsException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfNew(options.itemFactory.stringBuilderType), @@ -4256,6 +5314,15 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfReturn(ValueType.INT), label3), @@ -4280,6 +5347,14 @@ new CfLoad(ValueType.INT, 1), new CfIfCmp(If.Type.LT, ValueType.INT, label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/IndexOutOfBoundsException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfNew(options.itemFactory.stringBuilderType), @@ -4344,6 +5419,14 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfReturn(ValueType.INT), label3), @@ -4368,6 +5451,16 @@ new CfConstNumber(0, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/Comparator;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfLoad(ValueType.OBJECT, 0), new CfLoad(ValueType.OBJECT, 1), @@ -4382,6 +5475,16 @@ options.itemFactory.createString("compare")), true), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/Comparator;")) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -4441,11 +5544,27 @@ new CfConstNumber(1, ValueType.INT), new CfReturn(ValueType.INT), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfIf(If.Type.NE, ValueType.OBJECT, label2), new CfConstNumber(0, ValueType.INT), new CfReturn(ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.booleanArrayType), new CfIf(If.Type.EQ, ValueType.INT, label6), @@ -4471,10 +5590,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label5), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.byteArrayType), new CfIf(If.Type.EQ, ValueType.INT, label10), @@ -4500,10 +5643,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label9), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label9, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label10, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.charArrayType), new CfIf(If.Type.EQ, ValueType.INT, label14), @@ -4529,10 +5696,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label13), label12, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label13, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label14, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.doubleArrayType), new CfIf(If.Type.EQ, ValueType.INT, label18), @@ -4558,10 +5749,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label17), label16, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label17, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label18, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.floatArrayType), new CfIf(If.Type.EQ, ValueType.INT, label22), @@ -4587,10 +5802,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label21), label20, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label21, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label22, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.intArrayType), new CfIf(If.Type.EQ, ValueType.INT, label26), @@ -4616,10 +5855,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label25), label24, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label25, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label26, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.longArrayType), new CfIf(If.Type.EQ, ValueType.INT, label30), @@ -4645,10 +5908,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label29), label28, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label29, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label30, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.shortArrayType), new CfIf(If.Type.EQ, ValueType.INT, label34), @@ -4674,10 +5961,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label33), label32, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label33, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label34, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInstanceOf(options.itemFactory.createType("[Ljava/lang/Object;")), new CfIf(If.Type.EQ, ValueType.INT, label38), @@ -4703,10 +6014,34 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label37), label36, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label37, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label38, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( @@ -4752,11 +6087,35 @@ false), new CfIf(If.Type.EQ, ValueType.INT, label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(1, ValueType.INT), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label4), ImmutableList.of(), @@ -4779,6 +6138,11 @@ new CfConstNumber(0, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInvoke( 182, @@ -4788,6 +6152,11 @@ options.itemFactory.createString("hashCode")), false), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -4810,8 +6179,18 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -4834,8 +6213,18 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -4858,6 +6247,14 @@ new CfLoad(ValueType.OBJECT, 0), new CfReturn(ValueType.OBJECT), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.objectType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfConstString(options.itemFactory.createString("defaultObj")), new CfInvoke( @@ -4893,6 +6290,15 @@ new CfLoad(ValueType.OBJECT, 0), new CfReturn(ValueType.OBJECT), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/Supplier;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfConstString(options.itemFactory.createString("supplier")), new CfInvoke( @@ -4961,6 +6367,14 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.stringType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfReturn(ValueType.OBJECT), label3), @@ -5011,6 +6425,14 @@ new CfLoad(ValueType.OBJECT, 1), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.stringType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInvoke( 182, @@ -5020,6 +6442,14 @@ options.itemFactory.createString("toString")), false), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.objectType), + FrameType.initialized(options.itemFactory.stringType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.stringType))), new CfReturn(ValueType.OBJECT), label3), ImmutableList.of(), @@ -5067,6 +6497,16 @@ true), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Optional;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/Consumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -5076,6 +6516,16 @@ options.itemFactory.createString("run")), true), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Optional;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/Consumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfReturnVoid(), label4), ImmutableList.of(), @@ -5124,6 +6574,17 @@ true), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalDouble;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/DoubleConsumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -5133,6 +6594,17 @@ options.itemFactory.createString("run")), true), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalDouble;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/DoubleConsumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfReturnVoid(), label4), ImmutableList.of(), @@ -5181,6 +6653,17 @@ true), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalInt;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/IntConsumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -5190,6 +6673,17 @@ options.itemFactory.createString("run")), true), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalInt;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/IntConsumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfReturnVoid(), label4), ImmutableList.of(), @@ -5238,6 +6732,17 @@ true), new CfGoto(label3), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalLong;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/LongConsumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 185, @@ -5247,6 +6752,17 @@ options.itemFactory.createString("run")), true), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalLong;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/LongConsumer;")), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Runnable;")) + }), + Arrays.asList()), new CfReturnVoid(), label4), ImmutableList.of(), @@ -5276,8 +6792,22 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Optional;")) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Optional;")) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -5307,8 +6837,24 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalDouble;")) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalDouble;")) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -5338,8 +6884,24 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalInt;")) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalInt;")) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -5369,8 +6931,24 @@ new CfConstNumber(1, ValueType.INT), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalLong;")) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalLong;")) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label3), ImmutableList.of(), @@ -5414,6 +6992,15 @@ new CfLoad(ValueType.OBJECT, 0), new CfReturn(ValueType.OBJECT), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Optional;")), + FrameType.initialized( + options.itemFactory.createType("Ljava/util/function/Supplier;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfInvoke( 185, @@ -5481,6 +7068,13 @@ true), new CfReturn(ValueType.OBJECT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized(options.itemFactory.createType("Ljava/util/Optional;")) + }), + Arrays.asList()), new CfInvoke( 184, options.itemFactory.createMethod( @@ -5535,6 +7129,14 @@ true), new CfReturn(ValueType.OBJECT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalDouble;")) + }), + Arrays.asList()), new CfInvoke( 184, options.itemFactory.createMethod( @@ -5589,6 +7191,14 @@ true), new CfReturn(ValueType.OBJECT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalInt;")) + }), + Arrays.asList()), new CfInvoke( 184, options.itemFactory.createMethod( @@ -5643,6 +7253,14 @@ true), new CfReturn(ValueType.OBJECT), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType("Ljava/util/OptionalLong;")) + }), + Arrays.asList()), new CfInvoke( 184, options.itemFactory.createMethod( @@ -5757,6 +7375,11 @@ true), new CfGoto(label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInvoke( 184, @@ -5768,6 +7391,13 @@ options.itemFactory.createString("of")), true), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}), + Arrays.asList( + FrameType.initialized( + options.itemFactory.createType("Ljava/util/stream/Stream;")))), new CfReturn(ValueType.OBJECT), label3), ImmutableList.of(), @@ -5804,6 +7434,15 @@ false), new CfStore(ValueType.INT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 2), new CfIfCmp(If.Type.GE, ValueType.INT, label8), @@ -5834,6 +7473,16 @@ new CfConstNumber(0, ValueType.INT), new CfReturn(ValueType.INT), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 3), new CfInvoke( @@ -5849,6 +7498,11 @@ label7, new CfGoto(label2), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.stringType)}), + Arrays.asList()), new CfConstNumber(1, ValueType.INT), new CfReturn(ValueType.INT), label9), @@ -5889,6 +7543,15 @@ false), new CfThrow(), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized( + options.itemFactory.createType("[Ljava/lang/CharSequence;")) + }), + Arrays.asList()), new CfNew(options.itemFactory.stringBuilderType), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -5922,6 +7585,17 @@ new CfConstNumber(1, ValueType.INT), new CfStore(ValueType.INT, 3), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized( + options.itemFactory.createType("[Ljava/lang/CharSequence;")), + FrameType.initialized(options.itemFactory.stringBuilderType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 3), new CfLoad(ValueType.OBJECT, 1), new CfArrayLength(), @@ -5958,6 +7632,16 @@ new CfIinc(3, 1), new CfGoto(label5), label9, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized( + options.itemFactory.createType("[Ljava/lang/CharSequence;")), + FrameType.initialized(options.itemFactory.stringBuilderType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 182, @@ -6004,6 +7688,14 @@ false), new CfThrow(), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Iterable;")) + }), + Arrays.asList()), new CfNew(options.itemFactory.stringBuilderType), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -6057,6 +7749,16 @@ false), new CfStackInstruction(CfStackInstruction.Opcode.Pop), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Iterable;")), + FrameType.initialized(options.itemFactory.stringBuilderType), + FrameType.initialized(options.itemFactory.createType("Ljava/util/Iterator;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 3), new CfInvoke( 185, @@ -6102,6 +7804,16 @@ new CfStackInstruction(CfStackInstruction.Opcode.Pop), new CfGoto(label5), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.createType("Ljava/lang/Iterable;")), + FrameType.initialized(options.itemFactory.stringBuilderType), + FrameType.initialized(options.itemFactory.createType("Ljava/util/Iterator;")) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 2), new CfInvoke( 182, @@ -6186,6 +7898,14 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfInvoke( 182, @@ -6201,9 +7921,27 @@ new CfLoad(ValueType.INT, 2), new CfIf(If.Type.NE, ValueType.INT, label5), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstString(options.itemFactory.createString("")), new CfReturn(ValueType.OBJECT), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfConstNumber(1, ValueType.INT), new CfIfCmp(If.Type.NE, ValueType.INT, label7), @@ -6211,6 +7949,15 @@ new CfLoad(ValueType.OBJECT, 0), new CfReturn(ValueType.OBJECT), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.stringBuilderType), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfLoad(ValueType.INT, 2), @@ -6229,6 +7976,17 @@ new CfConstNumber(0, ValueType.INT), new CfStore(ValueType.INT, 4), label9, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.stringBuilderType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 4), new CfLoad(ValueType.INT, 1), new CfIfCmp(If.Type.GE, ValueType.INT, label12), @@ -6248,6 +8006,16 @@ new CfIinc(4, 1), new CfGoto(label9), label12, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.stringBuilderType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 3), new CfInvoke( 182, @@ -6298,6 +8066,15 @@ false), new CfStore(ValueType.INT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 2), new CfIfCmp(If.Type.GE, ValueType.INT, label8), @@ -6327,6 +8104,16 @@ label5, new CfGoto(label8), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 3), new CfInvoke( @@ -6342,6 +8129,15 @@ label7, new CfGoto(label2), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfLoad(ValueType.INT, 1), new CfIfCmp(If.Type.LE, ValueType.INT, label14), @@ -6373,6 +8169,16 @@ label11, new CfGoto(label14), label12, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfLoad(ValueType.INT, 3), new CfInvoke( @@ -6388,6 +8194,15 @@ label13, new CfGoto(label8), label14, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 2), @@ -6437,6 +8252,15 @@ false), new CfStore(ValueType.INT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 2), new CfIfCmp(If.Type.GE, ValueType.INT, label8), @@ -6466,6 +8290,16 @@ label5, new CfGoto(label8), label6, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 3), new CfInvoke( @@ -6481,6 +8315,15 @@ label7, new CfGoto(label2), label8, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 2), @@ -6526,6 +8369,14 @@ false), new CfStore(ValueType.INT, 1), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfIf(If.Type.LE, ValueType.INT, label7), label2, @@ -6556,6 +8407,15 @@ label4, new CfGoto(label7), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 1), new CfLoad(ValueType.INT, 2), new CfInvoke( @@ -6571,6 +8431,14 @@ label6, new CfGoto(label1), label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 0), new CfConstNumber(0, ValueType.INT), new CfLoad(ValueType.INT, 1),
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java index 1d32c0b..0968624 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -5,23 +5,24 @@ package com.android.tools.r8.ir.optimize; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; -import com.android.tools.r8.graph.DexEncodedField; +import com.android.tools.r8.graph.DexEncodedMember; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.FieldResolutionResult; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.ResolutionResult; -import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.ir.optimize.Inliner.Constraint; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import java.util.function.BiFunction; +import com.android.tools.r8.utils.TriFunction; // Computes the inlining constraint for a given instruction. public class InliningConstraints { @@ -131,8 +132,7 @@ } public ConstraintWithTarget forInstanceGet(DexField field, DexProgramClass context) { - DexField lookup = graphLens.lookupField(field); - return forFieldInstruction(lookup, appView.appInfo().lookupInstanceTarget(lookup), context); + return forFieldInstruction(field, context); } public ConstraintWithTarget forInstanceOf(DexType type, DexProgramClass context) { @@ -140,8 +140,7 @@ } public ConstraintWithTarget forInstancePut(DexField field, DexProgramClass context) { - DexField lookup = graphLens.lookupField(field); - return forFieldInstruction(lookup, appView.appInfo().lookupInstanceTarget(lookup), context); + return forFieldInstruction(field, context); } public ConstraintWithTarget forInvoke(DexMethod method, Type type, DexProgramClass context) { @@ -170,43 +169,16 @@ return ConstraintWithTarget.NEVER; } - private DexEncodedMethod lookupWhileVerticalClassMerging( - DexMethod method, - DexProgramClass context, - BiFunction<SingleResolutionResult, DexProgramClass, DexEncodedMethod> lookupFunction) { - SingleResolutionResult singleResolutionResult = - appView.appInfo().unsafeResolveMethodDueToDexFormat(method).asSingleResolution(); - if (singleResolutionResult == null) { - return null; - } - DexEncodedMethod dexEncodedMethod = lookupFunction.apply(singleResolutionResult, context); - if (dexEncodedMethod != null) { - return dexEncodedMethod; - } - assert graphLens.lookupType(context.superType) == context.type; - DexProgramClass superContext = appView.definitionForProgramType(context.superType); - if (superContext == null) { - return null; - } - DexEncodedMethod alternativeDexEncodedMethod = - lookupFunction.apply(singleResolutionResult, superContext); - if (alternativeDexEncodedMethod != null - && alternativeDexEncodedMethod.holder() == superContext.type) { - return alternativeDexEncodedMethod; - } - return null; - } - public ConstraintWithTarget forInvokeDirect(DexMethod method, DexProgramClass context) { DexMethod lookup = graphLens.lookupMethod(method); + if (lookup.holder.isArrayType()) { + return ConstraintWithTarget.ALWAYS; + } + ResolutionResult resolutionResult = appView.appInfo().unsafeResolveMethodDueToDexFormat(lookup); DexEncodedMethod target = - isVerticalClassMerging() - ? lookupWhileVerticalClassMerging( - lookup, - context, - (res, ctxt) -> res.lookupInvokeDirectTarget(ctxt, appView.appInfo())) - : appView.appInfo().lookupDirectTarget(lookup, context); - return forSingleTargetInvoke(lookup, target, context); + singleTargetWhileVerticalClassMerging( + resolutionResult, context, ResolutionResult::lookupInvokeDirectTarget); + return forResolvedMember(resolutionResult.getInitialResolutionHolder(), context, target); } public ConstraintWithTarget forInvokeInterface(DexMethod method, DexProgramClass context) { @@ -228,14 +200,49 @@ public ConstraintWithTarget forInvokeStatic(DexMethod method, DexProgramClass context) { DexMethod lookup = graphLens.lookupMethod(method); + if (lookup.holder.isArrayType()) { + return ConstraintWithTarget.ALWAYS; + } + ResolutionResult resolutionResult = appView.appInfo().unsafeResolveMethodDueToDexFormat(lookup); DexEncodedMethod target = - isVerticalClassMerging() - ? lookupWhileVerticalClassMerging( - lookup, - context, - (res, ctxt) -> res.lookupInvokeStaticTarget(ctxt, appView.appInfo())) - : appView.appInfo().lookupStaticTarget(lookup, context); - return forSingleTargetInvoke(lookup, target, context); + singleTargetWhileVerticalClassMerging( + resolutionResult, context, ResolutionResult::lookupInvokeStaticTarget); + if (!allowStaticInterfaceMethodCalls && target != null) { + // See b/120121170. + DexClass methodClass = appView.definitionFor(graphLens.lookupType(target.holder())); + if (methodClass != null && methodClass.isInterface() && target.hasCode()) { + return ConstraintWithTarget.NEVER; + } + } + return forResolvedMember(resolutionResult.getInitialResolutionHolder(), context, target); + } + + @SuppressWarnings("ConstantConditions") + private DexEncodedMethod singleTargetWhileVerticalClassMerging( + ResolutionResult resolutionResult, + DexProgramClass context, + TriFunction<ResolutionResult, DexProgramClass, AppInfoWithClassHierarchy, DexEncodedMethod> + lookup) { + if (!resolutionResult.isSingleResolution()) { + return null; + } + DexEncodedMethod dexEncodedMethod = lookup.apply(resolutionResult, context, appView.appInfo()); + if (!isVerticalClassMerging() || dexEncodedMethod != null) { + return dexEncodedMethod; + } + assert isVerticalClassMerging(); + assert graphLens.lookupType(context.superType) == context.type; + DexProgramClass superContext = appView.programDefinitionFor(context.superType, context); + if (superContext == null) { + return null; + } + DexEncodedMethod alternativeDexEncodedMethod = + lookup.apply(resolutionResult, superContext, appView.appInfo()); + if (alternativeDexEncodedMethod != null + && alternativeDexEncodedMethod.holder() == superContext.type) { + return alternativeDexEncodedMethod; + } + return null; } public ConstraintWithTarget forInvokeSuper(DexMethod method, DexProgramClass context) { @@ -293,13 +300,11 @@ } public ConstraintWithTarget forStaticGet(DexField field, DexProgramClass context) { - DexField lookup = graphLens.lookupField(field); - return forFieldInstruction(lookup, appView.appInfo().lookupStaticTarget(lookup), context); + return forFieldInstruction(field, context); } public ConstraintWithTarget forStaticPut(DexField field, DexProgramClass context) { - DexField lookup = graphLens.lookupField(field); - return forFieldInstruction(lookup, appView.appInfo().lookupStaticTarget(lookup), context); + return forFieldInstruction(field, context); } public ConstraintWithTarget forStore() { @@ -326,64 +331,13 @@ return ConstraintWithTarget.NEVER; } - private ConstraintWithTarget forFieldInstruction( - DexField field, DexEncodedField target, DexProgramClass context) { - // Resolve the field if possible and decide whether the instruction can inlined. - DexType fieldHolder = graphLens.lookupType(field.holder); - DexClass fieldClass = appView.definitionFor(fieldHolder); - if (target != null && fieldClass != null) { - ConstraintWithTarget fieldConstraintWithTarget = - ConstraintWithTarget.deriveConstraint(context, fieldHolder, target.accessFlags, appView); - - // If the field has not been member-rebound, then we also need to make sure that the - // `context` has access to the definition of the field. - // - // See, for example, InlineNonReboundFieldTest (b/128604123). - if (field.holder != target.holder()) { - DexType actualFieldHolder = graphLens.lookupType(target.holder()); - fieldConstraintWithTarget = - ConstraintWithTarget.meet( - fieldConstraintWithTarget, - ConstraintWithTarget.deriveConstraint( - context, actualFieldHolder, target.accessFlags, appView), - appView); - } - - ConstraintWithTarget classConstraintWithTarget = - ConstraintWithTarget.deriveConstraint( - context, fieldHolder, fieldClass.accessFlags, appView); - return ConstraintWithTarget.meet( - fieldConstraintWithTarget, classConstraintWithTarget, appView); - } - return ConstraintWithTarget.NEVER; - } - - private ConstraintWithTarget forSingleTargetInvoke( - DexMethod method, DexEncodedMethod target, DexProgramClass context) { - if (method.holder.isArrayType()) { - return ConstraintWithTarget.ALWAYS; - } - if (target != null) { - DexType methodHolder = graphLens.lookupType(target.holder()); - DexClass methodClass = appView.definitionFor(methodHolder); - if (methodClass != null) { - if (!allowStaticInterfaceMethodCalls && methodClass.isInterface() && target.hasCode()) { - // See b/120121170. - return ConstraintWithTarget.NEVER; - } - - ConstraintWithTarget methodConstraintWithTarget = - ConstraintWithTarget.deriveConstraint( - context, methodHolder, target.accessFlags, appView); - // We also have to take the constraint of the enclosing class into account. - ConstraintWithTarget classConstraintWithTarget = - ConstraintWithTarget.deriveConstraint( - context, methodHolder, methodClass.accessFlags, appView); - return ConstraintWithTarget.meet( - methodConstraintWithTarget, classConstraintWithTarget, appView); - } - } - return ConstraintWithTarget.NEVER; + private ConstraintWithTarget forFieldInstruction(DexField field, DexProgramClass context) { + DexField lookup = graphLens.lookupField(field); + FieldResolutionResult fieldResolutionResult = appView.appInfo().resolveField(lookup); + return forResolvedMember( + fieldResolutionResult.getInitialResolutionHolder(), + context, + fieldResolutionResult.getResolvedField()); } private ConstraintWithTarget forVirtualInvoke( @@ -399,27 +353,28 @@ return ConstraintWithTarget.NEVER; } - DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget(); - if (resolutionTarget == null) { + return forResolvedMember( + resolutionResult.getInitialResolutionHolder(), context, resolutionResult.getSingleTarget()); + } + + private ConstraintWithTarget forResolvedMember( + DexClass initialResolutionHolder, + DexProgramClass context, + DexEncodedMember<?, ?> resolvedMember) { + if (resolvedMember == null) { // This will fail at runtime. return ConstraintWithTarget.NEVER; } - - DexType methodHolder = graphLens.lookupType(resolutionTarget.holder()); - DexClass methodClass = appView.definitionFor(methodHolder); - assert methodClass != null; - ConstraintWithTarget methodConstraintWithTarget = + DexType resolvedHolder = graphLens.lookupType(resolvedMember.holder()); + assert initialResolutionHolder != null; + ConstraintWithTarget memberConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - context, methodHolder, resolutionTarget.accessFlags, appView); - // We also have to take the constraint of the enclosing class of the resolution result - // into account. We do not allow inlining this method if it is calling something that - // is inaccessible. Inlining in that case could move the code to another package making a - // call succeed that should not succeed. Conversely, if the resolution result is accessible, - // we have to make sure that inlining cannot make it inaccessible. + context, resolvedHolder, resolvedMember.getAccessFlags(), appView); + // We also have to take the constraint of the initial resolution holder into account. ConstraintWithTarget classConstraintWithTarget = ConstraintWithTarget.deriveConstraint( - context, methodHolder, methodClass.accessFlags, appView); + context, initialResolutionHolder.type, initialResolutionHolder.accessFlags, appView); return ConstraintWithTarget.meet( - methodConstraintWithTarget, classConstraintWithTarget, appView); + classConstraintWithTarget, memberConstraintWithTarget, appView); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java index c7e7b6b..7287edd 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -58,6 +58,7 @@ import com.android.tools.r8.ir.code.ValueTypeConstraint; import com.android.tools.r8.ir.conversion.IRBuilder; import com.android.tools.r8.ir.conversion.SourceCode; +import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.origin.Origin; @@ -1313,12 +1314,29 @@ public ProgramMethodSet selectMethodsForOutlining() { ProgramMethodSet methodsSelectedForOutlining = ProgramMethodSet.create(); assert outlineSites.isEmpty(); + + // TODO(b/167345026): This is needed to ensure that default interface methods are mapped to + // the corresponding companion methods that contain the code objects. This should be removed + // once default interface methods are desugared prior to the first optimization pass. + InterfaceProcessorNestedGraphLens interfaceProcessorLens = + InterfaceProcessorNestedGraphLens.find(appView.graphLens()); + if (interfaceProcessorLens != null) { + interfaceProcessorLens.toggleMappingToExtraMethods(); + } + for (LongLivedProgramMethodMultisetBuilder outlineMethods : candidateMethodLists) { if (outlineMethods.size() >= appView.options().outline.threshold) { ProgramMethodMultiset multiset = outlineMethods.build(appView); multiset.forEachEntry((method, ignore) -> methodsSelectedForOutlining.add(method)); } } + + // TODO(b/167345026): Remove once default interface methods are desugared prior to the first + // optimization pass. + if (interfaceProcessorLens != null) { + interfaceProcessorLens.toggleMappingToExtraMethods(); + } + candidateMethodLists.clear(); return methodsSelectedForOutlining; }
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 12b42aa..3d7d397 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
@@ -283,8 +283,11 @@ private void analyzeConstClass(ConstClass constClass, Set<DexType> eligibleEnums) { // We are using the ConstClass of an enum, which typically means the enum cannot be unboxed. - // We however allow unboxing if the ConstClass is only used as an argument to Enum#valueOf, to - // allow unboxing of: MyEnum a = Enum.valueOf(MyEnum.class, "A");. + // We however allow unboxing if the ConstClass is used only: + // - as an argument to Enum#valueOf, to allow unboxing of: + // MyEnum a = Enum.valueOf(MyEnum.class, "A"); + // - as a receiver for a name method, to allow unboxing of: + // MyEnum.class.getName(); DexType enumType = constClass.getValue(); if (!enumsUnboxingCandidates.containsKey(enumType)) { return; @@ -299,6 +302,10 @@ return; } for (Instruction user : constClass.outValue().uniqueUsers()) { + if (user.isInvokeVirtual() + && isUnboxableNameMethod(user.asInvokeVirtual().getInvokedMethod())) { + continue; + } if (!(user.isInvokeStatic() && user.asInvokeStatic().getInvokedMethod() == factory.enumMembers.valueOf)) { markEnumAsUnboxable(Reason.CONST_CLASS, enumClass); @@ -311,6 +318,12 @@ eligibleEnums.add(enumType); } + private boolean isUnboxableNameMethod(DexMethod method) { + return method == factory.classMethods.getName + || method == factory.classMethods.getCanonicalName + || method == factory.classMethods.getSimpleName; + } + private void addNullDependencies(IRCode code, Set<Instruction> uses, Set<DexType> eligibleEnums) { for (Instruction use : uses) { if (use.isInvokeMethod()) { @@ -372,7 +385,7 @@ } ImmutableSet<DexType> enumsToUnbox = ImmutableSet.copyOf(this.enumsUnboxingCandidates.keySet()); // Update keep info on any of the enum methods of the removed classes. - updatePinnedItems(enumsToUnbox); + updateKeepInfo(enumsToUnbox); enumUnboxerRewriter = new EnumUnboxingRewriter(appView, enumsToUnbox, enumInstanceFieldDataMap); DirectMappedDexApplication.Builder appBuilder = appView.appInfo().app().asDirect().builder(); Map<DexType, DexType> newMethodLocation = synthesizeUnboxedEnumsMethodsLocations(appBuilder); @@ -480,8 +493,7 @@ return syntheticClass; } - - private void updatePinnedItems(Set<DexType> enumsToUnbox) { + private void updateKeepInfo(Set<DexType> enumsToUnbox) { appView .appInfo() .getKeepInfo() @@ -490,8 +502,16 @@ for (DexType type : enumsToUnbox) { DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type)); assert !keepInfo.getClassInfo(clazz).isPinned(); - clazz.forEachProgramMethod(keepInfo::unsafeUnpinMethod); - clazz.forEachField(field -> keepInfo.unsafeUnpinField(clazz, field)); + clazz.forEachProgramMethod( + method -> { + keepInfo.unsafeAllowMinificationOfMethod(method); + keepInfo.unsafeUnpinMethod(method); + }); + clazz.forEachProgramField( + field -> { + keepInfo.unsafeAllowMinificationOfField(field); + keepInfo.unsafeUnpinField(field); + }); } }); } @@ -852,9 +872,20 @@ assert dexClass.isLibraryClass(); if (dexClass.type != factory.enumType) { // System.identityHashCode(Object) is supported for proto enums. + // Object#getClass without outValue and Objects.requireNonNull are supported since R8 + // rewrites explicit null checks to such instructions. if (singleTarget == factory.javaLangSystemMethods.identityHashCode) { return Reason.ELIGIBLE; } + if (singleTarget == factory.objectMembers.getClass + && (!invokeMethod.hasOutValue() || !invokeMethod.outValue().hasAnyUsers())) { + // This is a hidden null check. + return Reason.ELIGIBLE; + } + if (singleTarget == factory.objectsMethods.requireNonNull + || singleTarget == factory.objectsMethods.requireNonNullWithMessage) { + return Reason.ELIGIBLE; + } return Reason.UNSUPPORTED_LIBRARY_CALL; } // TODO(b/147860220): EnumSet and EnumMap may be interesting to model. @@ -873,9 +904,7 @@ return Reason.ELIGIBLE; } else if (singleTarget == factory.enumMembers.constructor) { // Enum constructor call is allowed only if first call of an enum initializer. - if (code.method().isInstanceInitializer() - && code.method().holder() == enumClass.type - && isFirstInstructionAfterArguments(invokeMethod, code)) { + if (code.method().isInstanceInitializer() && code.method().holder() == enumClass.type) { return Reason.ELIGIBLE; } } @@ -1076,16 +1105,6 @@ return ObjectState.empty(); } - private boolean isFirstInstructionAfterArguments(InvokeMethod invokeMethod, IRCode code) { - BasicBlock basicBlock = code.entryBlock(); - for (Instruction instruction : basicBlock.getInstructions()) { - if (!instruction.isArgument()) { - return instruction == invokeMethod; - } - } - return false; - } - private void reportEnumsAnalysis() { assert debugLogEnabled; Reporter reporter = appView.options().reporter;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java index a09ea37..922b5f0 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
@@ -12,6 +12,8 @@ import com.android.tools.r8.cf.code.CfArrayLength; import com.android.tools.r8.cf.code.CfArrayStore; import com.android.tools.r8.cf.code.CfConstNumber; +import com.android.tools.r8.cf.code.CfFrame; +import com.android.tools.r8.cf.code.CfFrame.FrameType; import com.android.tools.r8.cf.code.CfGoto; import com.android.tools.r8.cf.code.CfIf; import com.android.tools.r8.cf.code.CfIfCmp; @@ -22,6 +24,7 @@ import com.android.tools.r8.cf.code.CfNew; import com.android.tools.r8.cf.code.CfNewArray; import com.android.tools.r8.cf.code.CfReturn; +import com.android.tools.r8.cf.code.CfReturnVoid; import com.android.tools.r8.cf.code.CfStackInstruction; import com.android.tools.r8.cf.code.CfStore; import com.android.tools.r8.cf.code.CfThrow; @@ -34,6 +37,8 @@ import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; +import java.util.Arrays; public final class EnumUnboxingCfMethods { @@ -57,6 +62,14 @@ new CfLoad(ValueType.INT, 1), new CfIf(If.Type.NE, ValueType.INT, label2), label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfNew(options.itemFactory.createType("Ljava/lang/NullPointerException;")), new CfStackInstruction(CfStackInstruction.Opcode.Dup), new CfInvoke( @@ -68,6 +81,14 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfLoad(ValueType.INT, 1), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), @@ -104,14 +125,38 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfLoad(ValueType.INT, 1), new CfIfCmp(If.Type.NE, ValueType.INT, label3), new CfConstNumber(1, ValueType.INT), new CfGoto(label4), label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfConstNumber(0, ValueType.INT), label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList(FrameType.initialized(options.itemFactory.intType))), new CfReturn(ValueType.INT), label5), ImmutableList.of(), @@ -143,6 +188,11 @@ false), new CfThrow(), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList()), new CfLoad(ValueType.INT, 0), new CfConstNumber(1, ValueType.INT), new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), @@ -173,6 +223,15 @@ new CfConstNumber(0, ValueType.INT), new CfStore(ValueType.INT, 2), label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intArrayType), + FrameType.initialized(options.itemFactory.intType) + }), + Arrays.asList()), new CfLoad(ValueType.INT, 2), new CfLoad(ValueType.OBJECT, 1), new CfArrayLength(), @@ -188,10 +247,96 @@ new CfIinc(2, 1), new CfGoto(label2), label5, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intArrayType) + }), + Arrays.asList()), new CfLoad(ValueType.OBJECT, 1), new CfReturn(ValueType.OBJECT), label6), ImmutableList.of(), ImmutableList.of()); } + + public static CfCode EnumUnboxingMethods_zeroCheck(InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + return new CfCode( + method.holder, + 2, + 1, + ImmutableList.of( + label0, + new CfLoad(ValueType.INT, 0), + new CfIf(If.Type.NE, ValueType.INT, label2), + label1, + new CfNew(options.itemFactory.createType("Ljava/lang/NullPointerException;")), + new CfStackInstruction(CfStackInstruction.Opcode.Dup), + new CfInvoke( + 183, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/NullPointerException;"), + options.itemFactory.createProto(options.itemFactory.voidType), + options.itemFactory.createString("<init>")), + false), + new CfThrow(), + label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0}, + new FrameType[] {FrameType.initialized(options.itemFactory.intType)}), + Arrays.asList()), + new CfReturnVoid(), + label3), + ImmutableList.of(), + ImmutableList.of()); + } + + public static CfCode EnumUnboxingMethods_zeroCheckMessage( + InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + return new CfCode( + method.holder, + 3, + 2, + ImmutableList.of( + label0, + new CfLoad(ValueType.INT, 0), + new CfIf(If.Type.NE, ValueType.INT, label2), + label1, + new CfNew(options.itemFactory.createType("Ljava/lang/NullPointerException;")), + new CfStackInstruction(CfStackInstruction.Opcode.Dup), + new CfLoad(ValueType.OBJECT, 1), + new CfInvoke( + 183, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/NullPointerException;"), + options.itemFactory.createProto( + options.itemFactory.voidType, options.itemFactory.stringType), + options.itemFactory.createString("<init>")), + false), + new CfThrow(), + label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.stringType) + }), + Arrays.asList()), + new CfReturnVoid(), + label3), + ImmutableList.of(), + ImmutableList.of()); + } }
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 54d9aaf..ca106ab 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
@@ -77,6 +77,8 @@ private final DexMethod equalsUtilityMethod; private final DexMethod compareToUtilityMethod; private final DexMethod valuesUtilityMethod; + private final DexMethod zeroCheckMethod; + private final DexMethod zeroCheckMessageMethod; EnumUnboxingRewriter( AppView<AppInfoWithLiveness> appView, @@ -114,6 +116,17 @@ factory.enumUnboxingUtilityType, factory.createProto(factory.intArrayType, factory.intType), ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "values"); + // Custom methods for Object#getClass without outValue and Objects.requireNonNull. + this.zeroCheckMethod = + factory.createMethod( + factory.enumUnboxingUtilityType, + factory.createProto(factory.voidType, factory.intType), + ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheck"); + this.zeroCheckMessageMethod = + factory.createMethod( + factory.enumUnboxingUtilityType, + factory.createProto(factory.voidType, factory.intType, factory.stringType), + ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheckMessage"); } public EnumValueInfoMapCollection getEnumsToUnbox() { @@ -160,6 +173,10 @@ new InvokeStatic( toStringMethod, invokeMethod.outValue(), invokeMethod.arguments())); continue; + } else if (invokedMethod == factory.objectMembers.getClass) { + assert !invokeMethod.hasOutValue() || !invokeMethod.outValue().hasAnyUsers(); + replaceEnumInvoke( + iterator, invokeMethod, zeroCheckMethod, m -> synthesizeZeroCheckMethod()); } } // TODO(b/147860220): rewrite also other enum methods. @@ -195,6 +212,25 @@ invokeStatic.outValue().replaceUsers(argument); iterator.removeOrReplaceByDebugLocalRead(); } + } else if (invokedMethod == factory.objectsMethods.requireNonNull) { + assert invokeStatic.inValues().size() == 1; + Value argument = invokeStatic.getArgument(0); + DexType enumType = getEnumTypeOrNull(argument, convertedEnums); + if (enumType != null) { + replaceEnumInvoke( + iterator, invokeStatic, zeroCheckMethod, m -> synthesizeZeroCheckMethod()); + } + } else if (invokedMethod == factory.objectsMethods.requireNonNullWithMessage) { + assert invokeStatic.inValues().size() == 2; + Value argument = invokeStatic.getArgument(0); + DexType enumType = getEnumTypeOrNull(argument, convertedEnums); + if (enumType != null) { + replaceEnumInvoke( + iterator, + invokeStatic, + zeroCheckMessageMethod, + m -> synthesizeZeroCheckMessageMethod()); + } } } if (instruction.isStaticGet()) { @@ -497,6 +533,19 @@ return false; } + private DexEncodedMethod synthesizeZeroCheckMethod() { + CfCode cfCode = + EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheck(appView.options(), zeroCheckMethod); + return synthesizeUtilityMethod(cfCode, zeroCheckMethod, false); + } + + private DexEncodedMethod synthesizeZeroCheckMessageMethod() { + CfCode cfCode = + EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheckMessage( + appView.options(), zeroCheckMessageMethod); + return synthesizeUtilityMethod(cfCode, zeroCheckMessageMethod, false); + } + private DexEncodedMethod synthesizeOrdinalMethod() { CfCode cfCode = EnumUnboxingCfMethods.EnumUnboxingMethods_ordinal(appView.options(), ordinalUtilityMethod);
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java index 48f0d33..6f5a765 100644 --- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -22,6 +22,7 @@ import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode; +import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; @@ -73,10 +74,19 @@ this.keepInnerClassStructure = options.keepInnerClassStructure(); // Initialize top-level naming state. - topLevelState = - new Namespace( - getPackageBinaryNameFromJavaType( - options.getProguardConfiguration().getPackagePrefix())); + if (options.testing.enableExperimentalRepackaging) { + topLevelState = new Namespace(""); + String newPackageDescriptor = + StringUtils.replaceAll(options.getProguardConfiguration().getPackagePrefix(), ".", "/"); + if (!newPackageDescriptor.isEmpty()) { + registerPackagePrefixesAsUsed(newPackageDescriptor, false); + } + } else { + topLevelState = + new Namespace( + getPackageBinaryNameFromJavaType( + options.getProguardConfiguration().getPackagePrefix())); + } states.put("", topLevelState); @@ -199,7 +209,8 @@ private void registerClassAsUsed(DexType type, DexString descriptor) { renaming.put(type, descriptor); registerPackagePrefixesAsUsed( - getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString()))); + getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString())), + isAccessModificationAllowed); setUsedTypeName(descriptor.toString()); if (keepInnerClassStructure) { DexType outerClass = getOutClassForType(type); @@ -215,10 +226,10 @@ } /** Registers the given package prefix and all of parent packages as used. */ - private void registerPackagePrefixesAsUsed(String packagePrefix) { + private void registerPackagePrefixesAsUsed(String packagePrefix, boolean isMinificationAllowed) { // If -allowaccessmodification is not set, we may keep classes in their original packages, // accounting for package-private accesses. - if (!isAccessModificationAllowed) { + if (!isMinificationAllowed) { noObfuscationPrefixes.add(packagePrefix); } String usedPrefix = packagePrefix;
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java index 4077f36..5163a17 100644 --- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java +++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -5,12 +5,18 @@ package com.android.tools.r8.repackaging; import com.android.tools.r8.graph.AppView; +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.DirectMappedDexApplication; import com.android.tools.r8.graph.ProgramPackage; import com.android.tools.r8.graph.ProgramPackageCollection; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.ProguardConfiguration; +import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.Timing; +import java.util.IdentityHashMap; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -29,34 +35,52 @@ public class Repackaging { private final AppView<AppInfoWithLiveness> appView; + private final DexItemFactory dexItemFactory; private final ProguardConfiguration proguardConfiguration; public Repackaging(AppView<AppInfoWithLiveness> appView) { this.appView = appView; + this.dexItemFactory = appView.dexItemFactory(); this.proguardConfiguration = appView.options().getProguardConfiguration(); } - public void run(ExecutorService executorService, Timing timing) throws ExecutionException { + public RepackagingLens run( + DirectMappedDexApplication.Builder appBuilder, ExecutorService executorService, Timing timing) + throws ExecutionException { timing.begin("Repackage classes"); - run(executorService); + RepackagingLens lens = run(appBuilder, executorService); timing.end(); + return lens; } - private void run(ExecutorService executorService) throws ExecutionException { + private RepackagingLens run( + DirectMappedDexApplication.Builder appBuilder, ExecutorService executorService) + throws ExecutionException { if (proguardConfiguration.getPackageObfuscationMode().isNone()) { - return; + return null; } // For each package, find the set of classes that can be repackaged, and move them to the // desired namespace. - ProgramPackageCollection packages = ProgramPackageCollection.create(appView); - for (ProgramPackage pkg : packages) { + Map<DexType, DexType> mappings = new IdentityHashMap<>(); + for (ProgramPackage pkg : ProgramPackageCollection.create(appView)) { Iterable<DexProgramClass> classesToRepackage = computeClassesToRepackage(pkg, executorService); - // TODO(b/165783399): Move each class in `classesToRepackage`. + String newPackageDescriptor = getNewPackageDescriptor(pkg); + for (DexProgramClass classToRepackage : classesToRepackage) { + // TODO(b/165783399): Handle class collisions when different packages are repackaged into + // the same package. + DexType newType = + classToRepackage.getType().replacePackage(newPackageDescriptor, dexItemFactory); + mappings.put(classToRepackage.getType(), newType); + } // TODO(b/165783399): Investigate if repackaging can lead to different dynamic dispatch. See, // for example, CrossPackageInvokeSuperToPackagePrivateMethodTest. } + if (mappings.isEmpty()) { + return null; + } + return new RepackagingTreeFixer(appBuilder, appView, mappings).run(); } private Iterable<DexProgramClass> computeClassesToRepackage( @@ -69,4 +93,14 @@ constraintGraph.populateConstraints(executorService); return constraintGraph.computeClassesToRepackage(); } + + private String getNewPackageDescriptor(ProgramPackage pkg) { + String newPackageDescriptor = + StringUtils.replaceAll(proguardConfiguration.getPackagePrefix(), ".", "/"); + if (proguardConfiguration.getPackageObfuscationMode().isFlattenPackageHierarchy()) { + // TODO(b/165783399): Handle collisions among package names. + newPackageDescriptor += "/" + pkg.getLastPackageName(); + } + return newPackageDescriptor; + } }
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java index 9619f5a..33bbc11 100644 --- a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
@@ -14,9 +14,11 @@ import com.android.tools.r8.graph.ProgramPackage; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.ThreadUtils; +import com.android.tools.r8.utils.WorkList; import com.google.common.collect.Sets; -import java.util.Collections; +import java.util.ArrayList; import java.util.IdentityHashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -37,6 +39,7 @@ private final AppView<AppInfoWithLiveness> appView; private final ProgramPackage pkg; private final Map<DexDefinition, Node> nodes = new IdentityHashMap<>(); + private final Set<Node> pinnedNodes = Sets.newIdentityHashSet(); public RepackagingConstraintGraph(AppView<AppInfoWithLiveness> appView, ProgramPackage pkg) { this.appView = appView; @@ -48,19 +51,26 @@ // Add all the items in the package into the graph. This way we know which items belong to the // package without having to extract package descriptor strings and comparing them with the // package descriptor. - boolean hasPackagePrivateOrProtectedItem = false; boolean hasPinnedItem = false; for (DexProgramClass clazz : pkg) { boolean isPinned = !appView.appInfo().isMinificationAllowed(clazz.getType()); - hasPinnedItem |= isPinned; - nodes.put(clazz, new Node(clazz)); - hasPackagePrivateOrProtectedItem |= clazz.getAccessFlags().isPackagePrivateOrProtected(); - for (DexEncodedMember<?, ?> member : clazz.members()) { - nodes.put(member, new Node(member)); - hasPackagePrivateOrProtectedItem |= member.getAccessFlags().isPackagePrivateOrProtected(); + Node classNode = createNode(clazz); + if (isPinned) { + pinnedNodes.add(classNode); } + for (DexEncodedMember<?, ?> member : clazz.members()) { + Node memberNode = createNode(member); + classNode.addNeighbor(memberNode); + } + hasPinnedItem |= isPinned; } - return !hasPinnedItem || !hasPackagePrivateOrProtectedItem; + return !hasPinnedItem; + } + + private Node createNode(DexDefinition definition) { + Node node = new Node(definition); + nodes.put(definition, node); + return node; } Node getNode(DexDefinition definition) { @@ -101,9 +111,18 @@ } public Iterable<DexProgramClass> computeClassesToRepackage() { - // TODO(b/165783399): From each node in the graph that cannot be moved elsewhere due to a -keep - // rule, mark all neighbors as pinned, and repeat. - return Collections.emptyList(); + WorkList<Node> worklist = WorkList.newIdentityWorkList(pinnedNodes); + while (worklist.hasNext()) { + worklist.addIfNotSeen(worklist.next().getNeighbors()); + } + Set<Node> pinnedNodes = worklist.getSeenSet(); + List<DexProgramClass> classesToRepackage = new ArrayList<>(); + for (DexProgramClass clazz : pkg) { + if (!pinnedNodes.contains(getNode(clazz))) { + classesToRepackage.add(clazz); + } + } + return classesToRepackage; } static class Node { @@ -120,5 +139,9 @@ neighbors.add(neighbor); neighbor.neighbors.add(this); } + + public Set<Node> getNeighbors() { + return neighbors; + } } }
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java new file mode 100644 index 0000000..7c19b0b --- /dev/null +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -0,0 +1,66 @@ +// 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.repackaging; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +public class RepackagingLens extends NestedGraphLens { + + private final BiMap<DexType, DexType> originalTypes; + + private RepackagingLens( + AppView<AppInfoWithLiveness> appView, + BiMap<DexField, DexField> originalFieldSignatures, + BiMap<DexMethod, DexMethod> originalMethodSignatures, + BiMap<DexType, DexType> originalTypes) { + super( + originalTypes.inverse(), + originalMethodSignatures.inverse(), + originalFieldSignatures.inverse(), + originalFieldSignatures, + originalMethodSignatures, + appView.graphLens(), + appView.dexItemFactory()); + this.originalTypes = originalTypes; + } + + @Override + public DexType getOriginalType(DexType type) { + DexType previous = originalTypes.getOrDefault(type, type); + return previousLens.getOriginalType(previous); + } + + public static class Builder { + + protected final BiMap<DexType, DexType> originalTypes = HashBiMap.create(); + protected final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create(); + protected final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create(); + + public void recordMove(DexField from, DexField to) { + originalFieldSignatures.put(to, from); + } + + public void recordMove(DexMethod from, DexMethod to) { + originalMethodSignatures.put(to, from); + } + + public void recordMove(DexType from, DexType to) { + originalTypes.put(to, from); + } + + public RepackagingLens build(AppView<AppInfoWithLiveness> appView) { + assert !originalTypes.isEmpty(); + return new RepackagingLens( + appView, originalFieldSignatures, originalMethodSignatures, originalTypes); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java new file mode 100644 index 0000000..3591ff7 --- /dev/null +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
@@ -0,0 +1,281 @@ +// 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.repackaging; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexEncodedField; +import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexTypeList; +import com.android.tools.r8.graph.DirectMappedDexApplication; +import com.android.tools.r8.graph.EnclosingMethodAttribute; +import com.android.tools.r8.graph.InnerClassAttribute; +import com.android.tools.r8.graph.NestHostClassAttribute; +import com.android.tools.r8.graph.NestMemberClassAttribute; +import com.android.tools.r8.shaking.AnnotationFixer; +import com.android.tools.r8.shaking.AppInfoWithLiveness; +import java.util.ArrayList; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +public class RepackagingTreeFixer { + + private final DirectMappedDexApplication.Builder appBuilder; + private final AppView<AppInfoWithLiveness> appView; + private final DexItemFactory dexItemFactory; + private final RepackagingLens.Builder lensBuilder = new RepackagingLens.Builder(); + private final Map<DexType, DexType> repackagedClasses; + + private final Map<DexType, DexProgramClass> newProgramClasses = new IdentityHashMap<>(); + private final Map<DexProto, DexProto> protoFixupCache = new IdentityHashMap<>(); + + public RepackagingTreeFixer( + DirectMappedDexApplication.Builder appBuilder, + AppView<AppInfoWithLiveness> appView, + Map<DexType, DexType> repackagedClasses) { + this.appBuilder = appBuilder; + this.appView = appView; + this.dexItemFactory = appView.dexItemFactory(); + this.repackagedClasses = repackagedClasses; + } + + public RepackagingLens run() { + // Globally substitute repackaged class types. + for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) { + newProgramClasses.computeIfAbsent(clazz.getType(), ignore -> fixupClass(clazz)); + } + appBuilder.replaceProgramClasses(new ArrayList<>(newProgramClasses.values())); + RepackagingLens lens = lensBuilder.build(appView); + new AnnotationFixer(lens).run(appView.appInfo().classes()); + return lens; + } + + private DexProgramClass fixupClass(DexProgramClass clazz) { + DexProgramClass newClass = + new DexProgramClass( + fixupType(clazz.getType()), + clazz.getOriginKind(), + clazz.getOrigin(), + clazz.getAccessFlags(), + fixupType(clazz.superType), + fixupTypeList(clazz.interfaces), + clazz.getSourceFile(), + fixupNestHost(clazz.getNestHost()), + fixupNestMemberAttributes(clazz.getNestMembersClassAttributes()), + fixupEnclosingMethodAttribute(clazz.getEnclosingMethodAttribute()), + fixupInnerClassAttributes(clazz.getInnerClasses()), + clazz.annotations(), + DexEncodedField.EMPTY_ARRAY, + DexEncodedField.EMPTY_ARRAY, + DexEncodedMethod.EMPTY_ARRAY, + DexEncodedMethod.EMPTY_ARRAY, + dexItemFactory.getSkipNameValidationForTesting(), + DexProgramClass::checksumFromType, + fixupSynthesizedFrom(clazz.getSynthesizedFrom())); + newClass.setInstanceFields(fixupFields(clazz.instanceFields())); + newClass.setStaticFields(fixupFields(clazz.staticFields())); + newClass.setDirectMethods( + fixupMethods( + clazz.getMethodCollection().directMethods(), + clazz.getMethodCollection().numberOfDirectMethods())); + newClass.setVirtualMethods( + fixupMethods( + clazz.getMethodCollection().virtualMethods(), + clazz.getMethodCollection().numberOfVirtualMethods())); + if (newClass.getType() != clazz.getType()) { + lensBuilder.recordMove(clazz.getType(), newClass.getType()); + } + return newClass; + } + + private EnclosingMethodAttribute fixupEnclosingMethodAttribute( + EnclosingMethodAttribute enclosingMethodAttribute) { + if (enclosingMethodAttribute == null) { + return null; + } + DexType enclosingClassType = enclosingMethodAttribute.getEnclosingClass(); + if (enclosingClassType != null) { + DexType newEnclosingClassType = fixupType(enclosingClassType); + return newEnclosingClassType != enclosingClassType + ? new EnclosingMethodAttribute(newEnclosingClassType) + : enclosingMethodAttribute; + } + DexMethod enclosingMethod = enclosingMethodAttribute.getEnclosingMethod(); + assert enclosingMethod != null; + DexMethod newEnclosingMethod = + fixupMethodReference(enclosingMethodAttribute.getEnclosingMethod()); + return newEnclosingMethod != enclosingMethod + ? new EnclosingMethodAttribute(newEnclosingMethod) + : enclosingMethodAttribute; + } + + private DexEncodedField[] fixupFields(List<DexEncodedField> fields) { + if (fields == null) { + return DexEncodedField.EMPTY_ARRAY; + } + DexEncodedField[] newFields = new DexEncodedField[fields.size()]; + for (int i = 0; i < fields.size(); i++) { + newFields[i] = fixupField(fields.get(i)); + } + return newFields; + } + + private DexEncodedField fixupField(DexEncodedField field) { + DexField fieldReference = field.toReference(); + DexField newFieldReference = fixupFieldReference(fieldReference); + if (newFieldReference != fieldReference) { + lensBuilder.recordMove(fieldReference, newFieldReference); + return field.toTypeSubstitutedField(newFieldReference); + } + return field; + } + + private DexField fixupFieldReference(DexField field) { + DexType newType = fixupType(field.type); + DexType newHolder = fixupType(field.holder); + return dexItemFactory.createField(newHolder, newType, field.name); + } + + private List<InnerClassAttribute> fixupInnerClassAttributes( + List<InnerClassAttribute> innerClassAttributes) { + if (innerClassAttributes.isEmpty()) { + return innerClassAttributes; + } + boolean changed = false; + List<InnerClassAttribute> newInnerClassAttributes = new ArrayList<>(); + for (InnerClassAttribute innerClassAttribute : innerClassAttributes) { + DexType innerClassType = innerClassAttribute.getInner(); + DexType newInnerClassType = fixupType(innerClassType); + DexType outerClassType = innerClassAttribute.getOuter(); + DexType newOuterClassType = fixupType(outerClassType); + newInnerClassAttributes.add( + new InnerClassAttribute( + innerClassAttribute.getAccess(), + newInnerClassType, + newOuterClassType, + innerClassAttribute.getInnerName())); + changed |= newInnerClassType != innerClassType || newOuterClassType != outerClassType; + } + return changed ? newInnerClassAttributes : innerClassAttributes; + } + + private DexEncodedMethod[] fixupMethods(Iterable<DexEncodedMethod> methods, int size) { + if (size == 0) { + return DexEncodedMethod.EMPTY_ARRAY; + } + int i = 0; + DexEncodedMethod[] newMethods = new DexEncodedMethod[size]; + for (DexEncodedMethod method : methods) { + newMethods[i++] = fixupMethod(method); + } + return newMethods; + } + + private DexEncodedMethod fixupMethod(DexEncodedMethod method) { + DexMethod methodReference = method.toReference(); + DexMethod newMethodReference = fixupMethodReference(methodReference); + if (newMethodReference != methodReference) { + lensBuilder.recordMove(methodReference, newMethodReference); + return method.toTypeSubstitutedMethod(newMethodReference); + } + return method; + } + + private DexMethod fixupMethodReference(DexMethod method) { + return appView + .dexItemFactory() + .createMethod(fixupType(method.holder), fixupProto(method.proto), method.name); + } + + private NestHostClassAttribute fixupNestHost(DexType type) { + return type != null ? new NestHostClassAttribute(fixupType(type)) : null; + } + + private List<NestMemberClassAttribute> fixupNestMemberAttributes( + List<NestMemberClassAttribute> nestMemberAttributes) { + if (nestMemberAttributes.isEmpty()) { + return nestMemberAttributes; + } + boolean changed = false; + List<NestMemberClassAttribute> newNestMemberAttributes = + new ArrayList<>(nestMemberAttributes.size()); + for (NestMemberClassAttribute nestMemberAttribute : nestMemberAttributes) { + DexType nestMemberType = nestMemberAttribute.getNestMember(); + DexType newNestMemberType = fixupType(nestMemberType); + newNestMemberAttributes.add(new NestMemberClassAttribute(newNestMemberType)); + changed |= newNestMemberType != nestMemberType; + } + return changed ? newNestMemberAttributes : nestMemberAttributes; + } + + private DexProto fixupProto(DexProto proto) { + DexProto result = protoFixupCache.get(proto); + if (result == null) { + DexType returnType = fixupType(proto.returnType); + DexType[] arguments = fixupTypes(proto.parameters.values); + result = dexItemFactory.createProto(returnType, arguments); + protoFixupCache.put(proto, result); + } + return result; + } + + private Collection<DexProgramClass> fixupSynthesizedFrom( + Collection<DexProgramClass> synthesizedFrom) { + if (synthesizedFrom.isEmpty()) { + return synthesizedFrom; + } + boolean changed = false; + List<DexProgramClass> newSynthesizedFrom = new ArrayList<>(synthesizedFrom.size()); + for (DexProgramClass clazz : synthesizedFrom) { + // TODO(b/165783399): What do we want to put here if the class that this was synthesized from + // is no longer in the application? + assert appView.definitionFor(clazz.type) != null; + DexProgramClass newClass = + newProgramClasses.computeIfAbsent(clazz.getType(), ignore -> fixupClass(clazz)); + newSynthesizedFrom.add(newClass); + changed |= newClass != clazz; + } + return changed ? newSynthesizedFrom : synthesizedFrom; + } + + private DexType fixupType(DexType type) { + if (type.isArrayType()) { + DexType base = type.toBaseType(dexItemFactory); + DexType fixed = fixupType(base); + if (base == fixed) { + return type; + } + return type.replaceBaseType(fixed, dexItemFactory); + } + if (type.isClassType()) { + return repackagedClasses.getOrDefault(type, type); + } + return type; + } + + private DexType[] fixupTypes(DexType[] types) { + boolean changed = false; + DexType[] newTypes = new DexType[types.length]; + for (int i = 0; i < newTypes.length; i++) { + DexType type = types[i]; + DexType newType = fixupType(types[i]); + newTypes[i] = newType; + changed |= newType != type; + } + return changed ? newTypes : types; + } + + private DexTypeList fixupTypeList(DexTypeList types) { + DexType[] newTypes = fixupTypes(types.values); + return newTypes != types.values ? new DexTypeList(newTypes) : types; + } +}
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 6768368..05c6f6c 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1025,7 +1025,7 @@ // TODO(sgjesse): Rewrite call sites as well? Right now they are only used by minification // after second tree shaking. callSites, - keepInfo.rewrite(lens), + keepInfo.rewrite(lens, application.options), lens.rewriteReferenceKeys(mayHaveSideEffects), lens.rewriteReferenceKeys(noSideEffects), lens.rewriteReferenceKeys(assumedValues),
diff --git a/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java b/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java new file mode 100644 index 0000000..4e9d977 --- /dev/null +++ b/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java
@@ -0,0 +1,96 @@ +// 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.AppView; +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl; +import com.android.tools.r8.graph.FieldAccessInfoImpl; +import com.android.tools.r8.graph.ProgramMethod; +import java.util.ArrayList; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class FieldAccessInfoCollectionModifier { + + static class FieldReferences { + final List<DexMethod> writeContexts = new ArrayList<>(); + final List<DexMethod> readContexts = new ArrayList<>(); + + void fixUpMethods(List<DexMethod> methods, Function<DexMethod, DexMethod> fixUpMethod) { + for (int i = 0; i < methods.size(); i++) { + DexMethod method = methods.get(i); + DexMethod newMethod = fixUpMethod.apply(method); + if (method != newMethod) { + methods.set(i, newMethod); + } + } + } + + void fixUp(Function<DexMethod, DexMethod> fixUpMethod) { + fixUpMethods(writeContexts, fixUpMethod); + fixUpMethods(readContexts, fixUpMethod); + } + } + + final Map<DexField, FieldReferences> newFieldAccesses; + + FieldAccessInfoCollectionModifier(Map<DexField, FieldReferences> newFieldAccesses) { + this.newFieldAccesses = newFieldAccesses; + } + + void forEachFieldAccess( + AppView<?> appView, + Collection<DexMethod> methods, + DexField field, + BiConsumer<DexField, ProgramMethod> record) { + for (DexMethod method : methods) { + ProgramMethod programMethod = + appView.definitionFor(method.holder).asProgramClass().lookupProgramMethod(method); + record.accept(field, programMethod); + } + } + + public void modify(AppView<AppInfoWithLiveness> appView) { + FieldAccessInfoCollectionImpl impl = appView.appInfo().getMutableFieldAccessInfoCollection(); + newFieldAccesses.forEach( + (field, info) -> { + FieldAccessInfoImpl fieldAccessInfo = new FieldAccessInfoImpl(field); + forEachFieldAccess(appView, info.readContexts, field, fieldAccessInfo::recordRead); + forEachFieldAccess(appView, info.writeContexts, field, fieldAccessInfo::recordWrite); + impl.extend(field, fieldAccessInfo); + }); + } + + public static class Builder { + final Map<DexField, FieldReferences> newFieldAccesses = new IdentityHashMap<>(); + + public Builder() {} + + public FieldAccessInfoCollectionModifier build(Function<DexMethod, DexMethod> fixupMethod) { + for (FieldReferences fieldReference : newFieldAccesses.values()) { + fieldReference.fixUp(fixupMethod); + } + return new FieldAccessInfoCollectionModifier(newFieldAccesses); + } + + FieldReferences getFieldReferences(DexField field) { + return newFieldAccesses.computeIfAbsent(field, ignore -> new FieldReferences()); + } + + public void fieldReadByMethod(DexField field, DexMethod method) { + getFieldReferences(field).readContexts.add(method); + } + + public void fieldWrittenByMethod(DexField field, DexMethod method) { + getFieldReferences(field).writeContexts.add(method); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java index ee30fce..efc610a 100644 --- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -20,6 +20,8 @@ import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.shaking.KeepFieldInfo.Joiner; +import com.android.tools.r8.utils.InternalOptions; +import com.google.common.collect.Streams; import java.util.ArrayList; import java.util.Collection; import java.util.IdentityHashMap; @@ -160,7 +162,7 @@ @Deprecated public abstract void forEachPinnedField(Consumer<DexField> consumer); - public abstract KeepInfoCollection rewrite(NestedGraphLens lens); + public abstract KeepInfoCollection rewrite(NestedGraphLens lens, InternalOptions options); public abstract KeepInfoCollection mutate(Consumer<MutableKeepInfoCollection> mutator); @@ -196,26 +198,39 @@ } @Override - public KeepInfoCollection rewrite(NestedGraphLens lens) { + public KeepInfoCollection rewrite(NestedGraphLens lens, InternalOptions options) { Map<DexType, KeepClassInfo> newClassInfo = new IdentityHashMap<>(keepClassInfo.size()); keepClassInfo.forEach( (type, info) -> { DexType newType = lens.lookupType(type); - assert !info.isPinned() || type == newType; + assert newType == type || !info.isPinned() || info.isMinificationAllowed(options); newClassInfo.put(newType, info); }); Map<DexMethod, KeepMethodInfo> newMethodInfo = new IdentityHashMap<>(keepMethodInfo.size()); keepMethodInfo.forEach( (method, info) -> { DexMethod newMethod = lens.getRenamedMethodSignature(method); - assert !info.isPinned() || method == newMethod; + assert !info.isPinned() + || info.isMinificationAllowed(options) + || newMethod.name == method.name; + assert !info.isPinned() || newMethod.getArity() == method.getArity(); + assert !info.isPinned() + || Streams.zip( + newMethod.getParameters().stream(), + method.getParameters().stream().map(lens::lookupType), + Object::equals) + .allMatch(x -> x); + assert !info.isPinned() + || newMethod.getReturnType() == lens.lookupType(method.getReturnType()); newMethodInfo.put(newMethod, info); }); Map<DexField, KeepFieldInfo> newFieldInfo = new IdentityHashMap<>(keepFieldInfo.size()); keepFieldInfo.forEach( (field, info) -> { DexField newField = lens.getRenamedFieldSignature(field); - assert !info.isPinned() || field == newField; + assert newField.name == field.name + || !info.isPinned() + || info.isMinificationAllowed(options); newFieldInfo.put(newField, info); }); Map<DexReference, List<Consumer<KeepInfo.Joiner<?, ?, ?>>>> newRuleInstances = @@ -353,6 +368,13 @@ joinMethod(holder, method, KeepInfo.Joiner::pin); } + public void unsafeAllowMinificationOfMethod(ProgramMethod method) { + KeepMethodInfo info = keepMethodInfo.get(method.getReference()); + if (info != null && !info.internalIsMinificationAllowed()) { + keepMethodInfo.put(method.getReference(), info.builder().allowMinification().build()); + } + } + // Unpinning a method represents a non-monotonic change to the keep info of that item. // This is generally unsound as it requires additional analysis to determine that a method that // was pinned no longer is. A known sound example is the enum analysis that will identify @@ -409,12 +431,19 @@ } } - public void unsafeUnpinField(DexProgramClass holder, DexEncodedField field) { - assert holder.type == field.holder(); - assert !getClassInfo(holder).isPinned(); - KeepFieldInfo info = this.keepFieldInfo.get(field.toReference()); + public void unsafeAllowMinificationOfField(ProgramField field) { + assert !getClassInfo(field.getHolder()).isPinned(); + KeepFieldInfo info = keepFieldInfo.get(field.getReference()); + if (info != null && !info.internalIsMinificationAllowed()) { + keepFieldInfo.put(field.getReference(), info.builder().allowAccessModification().build()); + } + } + + public void unsafeUnpinField(ProgramField field) { + assert !getClassInfo(field.getHolder()).isPinned(); + KeepFieldInfo info = this.keepFieldInfo.get(field.getReference()); if (info != null && info.isPinned()) { - keepFieldInfo.put(field.toReference(), info.builder().unpin().build()); + keepFieldInfo.put(field.getReference(), info.builder().unpin().build()); } }
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java index 08830cc..db43676 100644 --- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java +++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -8,13 +8,11 @@ import com.android.tools.r8.Diagnostic; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.AppInfo; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.BottomUpClassHierarchyTraversal; import com.android.tools.r8.graph.DexAnnotation; import com.android.tools.r8.graph.DexAnnotationSet; -import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexDefinition; import com.android.tools.r8.graph.DexDefinitionSupplier; @@ -29,6 +27,7 @@ import com.android.tools.r8.graph.DexReference; 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.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult; import com.android.tools.r8.graph.SubtypingInfo; @@ -1962,26 +1961,30 @@ return false; } - public boolean verifyKeptItemsAreKept(DexApplication application, AppInfo appInfo) { + public boolean verifyKeptItemsAreKept(AppView<? extends AppInfoWithClassHierarchy> appView) { + AppInfoWithClassHierarchy appInfo = appView.appInfo(); + GraphLens lens = appView.graphLens(); // Create a mapping from each required type to the set of required members on that type. Map<DexType, Set<DexMember<?, ?>>> requiredMembersPerType = new IdentityHashMap<>(); noShrinking.forEachClass( type -> { - assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(type) - : "Expected reference `" + type.toSourceString() + "` to be pinned"; - requiredMembersPerType.computeIfAbsent(type, key -> Sets.newIdentityHashSet()); + DexType rewrittenType = lens.lookupType(type); + assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(rewrittenType) + : "Expected reference `" + rewrittenType.toSourceString() + "` to be pinned"; + requiredMembersPerType.computeIfAbsent(rewrittenType, key -> Sets.newIdentityHashSet()); }); noShrinking.forEachMember( member -> { - assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(member) - : "Expected reference `" + member.toSourceString() + "` to be pinned"; + DexMember<?, ?> rewrittenMember = lens.getRenamedMemberSignature(member); + assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(rewrittenMember) + : "Expected reference `" + rewrittenMember.toSourceString() + "` to be pinned"; requiredMembersPerType - .computeIfAbsent(member.holder, key -> Sets.newIdentityHashSet()) - .add(member); + .computeIfAbsent(rewrittenMember.holder, key -> Sets.newIdentityHashSet()) + .add(rewrittenMember); }); // Run through each class in the program and check that it has members it must have. - for (DexProgramClass clazz : application.classes()) { + for (DexProgramClass clazz : appView.appInfo().classes()) { Set<DexMember<?, ?>> requiredMembers = requiredMembersPerType.getOrDefault(clazz.type, ImmutableSet.of()); @@ -2023,7 +2026,7 @@ // If the map is non-empty, then a type in the root set was not in the application. if (!requiredMembersPerType.isEmpty()) { DexType type = requiredMembersPerType.keySet().iterator().next(); - DexClass clazz = application.definitionFor(type); + DexClass clazz = appView.definitionFor(type); assert clazz == null || clazz.isProgramClass() : "Unexpected library type in root set: `" + type + "`"; assert requiredMembersPerType.isEmpty()
diff --git a/src/main/java/com/android/tools/r8/utils/MapUtils.java b/src/main/java/com/android/tools/r8/utils/MapUtils.java new file mode 100644 index 0000000..3929e87 --- /dev/null +++ b/src/main/java/com/android/tools/r8/utils/MapUtils.java
@@ -0,0 +1,14 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.utils; + +import java.util.Map; + +public class MapUtils { + + public static <T> void removeIdentityMappings(Map<T, T> map) { + map.entrySet().removeIf(entry -> entry.getKey() == entry.getValue()); + } +}
diff --git a/src/test/java/com/android/tools/r8/AsmTestBase.java b/src/test/java/com/android/tools/r8/AsmTestBase.java index 6195ea0..4a24331 100644 --- a/src/test/java/com/android/tools/r8/AsmTestBase.java +++ b/src/test/java/com/android/tools/r8/AsmTestBase.java
@@ -21,18 +21,6 @@ public class AsmTestBase extends TestBase { - protected void ensureException(String main, Class<? extends Throwable> exceptionClass, - byte[]... classes) throws Exception { - ensureExceptionThrown(runOnJavaRaw(main, classes), exceptionClass); - AndroidApp app = buildAndroidApp(classes); - ensureExceptionThrown(runOnArtRaw(compileWithD8(app), main), exceptionClass); - ensureExceptionThrown(runOnArtRaw(compileWithR8(app), main), exceptionClass); - ensureExceptionThrown( - runOnArtRaw(compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"), - main), - exceptionClass); - } - protected void ensureSameOutput(String main, AndroidApiLevel apiLevel, byte[]... classes) throws Exception { ensureSameOutput(main, apiLevel, Collections.emptyList(), classes);
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java index e59ea66..8698d61 100644 --- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java +++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -167,6 +167,10 @@ return self(); } + public JvmTestBuilder noVerify() { + return addVmArguments("-noverify"); + } + public JvmTestBuilder addAndroidBuildVersion() { addVmArguments("-D" + AndroidBuildVersion.PROPERTY + "=10000"); return addProgramClasses(AndroidBuildVersion.class);
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java index 1631830..c83cd38 100644 --- a/src/test/java/com/android/tools/r8/L8CommandTest.java +++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -4,6 +4,8 @@ package com.android.tools.r8; import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage; +import static com.android.tools.r8.MarkerMatcher.assertMarkersMatch; +import static com.android.tools.r8.MarkerMatcher.markerTool; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -14,11 +16,13 @@ import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation; import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope; import com.android.tools.r8.dex.Marker; +import com.android.tools.r8.dex.Marker.Tool; import com.android.tools.r8.origin.EmbeddedOrigin; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.FileUtils; import com.android.tools.r8.utils.ThreadUtils; +import com.google.common.collect.ImmutableList; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -26,7 +30,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -66,7 +69,7 @@ } @Test - public void testMarker() throws Throwable { + public void testDexMarker() throws Throwable { Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip"); L8.run( L8Command.builder() @@ -77,14 +80,28 @@ StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) .setOutput(output, OutputMode.DexIndexed) .build()); - Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output); - // TODO(b/134732760): Shouldn't we remove the D8/R8 marker? - assertEquals(2, markers.size()); - Marker marker = markers.iterator().next(); + assertMarkersMatch( + ExtractMarker.extractMarkerFromDexFile(output), + ImmutableList.of(markerTool(Tool.L8), markerTool(Tool.D8))); } @Test - public void testMarkerCommandLine() throws Throwable { + public void testClassFileMarker() throws Throwable { + Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip"); + L8.run( + L8Command.builder() + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) + .addProgramFiles(ToolHelper.getDesugarJDKLibs()) + .setMinApiLevel(20) + .addDesugaredLibraryConfiguration( + StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) + .setOutput(output, OutputMode.ClassFile) + .build()); + assertMarkersMatch(ExtractMarker.extractMarkerFromDexFile(output), markerTool(Tool.L8)); + } + + @Test + public void testDexMarkerCommandLine() throws Throwable { Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip"); L8Command l8Command = parse( @@ -99,9 +116,28 @@ output.toString()); L8.run(l8Command); Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output); - // TODO(b/134732760): Shouldn't we remove the D8/R8 marker? - assertEquals(2, markers.size()); - Marker marker = markers.iterator().next(); + assertMarkersMatch( + ExtractMarker.extractMarkerFromDexFile(output), + ImmutableList.of(markerTool(Tool.L8), markerTool(Tool.D8))); + } + + @Test + public void testClassFileMarkerCommandLine() throws Throwable { + Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip"); + L8Command l8Command = + parse( + ToolHelper.getDesugarJDKLibs().toString(), + "--lib", + ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(), + "--min-api", + "20", + "--desugared-lib", + ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(), + "--output", + output.toString(), + "--classfile"); + L8.run(l8Command); + assertMarkersMatch(ExtractMarker.extractMarkerFromDexFile(output), markerTool(Tool.L8)); } @Test @@ -118,6 +154,26 @@ } @Test + public void testFlagPgConfWithClassFile() throws Exception { + TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl(); + try { + Path pgconf = temp.newFolder().toPath().resolve("pg.conf"); + FileUtils.writeTextFile(pgconf, ""); + parse( + diagnostics, + "--desugared-lib", + ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(), + "--pg-conf", + pgconf.toString(), + "--classfile"); + fail("Expected failure"); + } catch (CompilationFailedException e) { + diagnostics.assertErrorsMatch( + diagnosticMessage(containsString("not support shrinking when generating class files"))); + } + } + + @Test public void testFlagPgConfMissingParameter() { TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl(); try { @@ -162,14 +218,6 @@ } @Test(expected = CompilationFailedException.class) - public void classFileOutputNotSupported() throws Throwable { - DiagnosticsChecker.checkErrorsContains( - "L8 does not support compiling to class files", - (handler) -> - prepareBuilder(handler).setProgramConsumer(ClassFileConsumer.emptyConsumer()).build()); - } - - @Test(expected = CompilationFailedException.class) public void desugaredLibraryConfigurationRequired() throws Throwable { DiagnosticsChecker.checkErrorsContains( "L8 requires a desugared library configuration", @@ -177,15 +225,14 @@ prepareBuilder(handler).setProgramConsumer(ClassFileConsumer.emptyConsumer()).build()); } - @Test - @Ignore("b/143431384: Re-enable shrinking") - public void addProguardConfigurationString() throws Throwable { + private void addProguardConfigurationString( + DiagnosticsHandler diagnostics, ProgramConsumer programConsumer) throws Throwable { String keepRule = "-keep class java.time.*"; List<String> keepRules = new ArrayList<>(); keepRules.add(keepRule); L8Command.Builder builder = - prepareBuilder(new TestDiagnosticMessagesImpl()) - .setProgramConsumer(DexIndexedConsumer.emptyConsumer()) + prepareBuilder(diagnostics) + .setProgramConsumer(programConsumer) .addDesugaredLibraryConfiguration( StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) .addProguardConfiguration(keepRules, Origin.unknown()); @@ -194,15 +241,32 @@ } @Test - @Ignore("b/143431384: Re-enable shrinking") - public void addProguardConfigurationFile() throws Throwable { + public void addProguardConfigurationStringWithDex() throws Throwable { + addProguardConfigurationString( + new TestDiagnosticMessagesImpl(), DexIndexedConsumer.emptyConsumer()); + } + + @Test + public void addProguardConfigurationStringWithClassFile() throws Throwable { + TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl(); + try { + addProguardConfigurationString(diagnostics, ClassFileConsumer.emptyConsumer()); + fail("Expected failure"); + } catch (CompilationFailedException e) { + diagnostics.assertErrorsMatch( + diagnosticMessage(containsString("not support shrinking when generating class files"))); + } + } + + private void addProguardConfigurationFile( + DiagnosticsHandler diagnostics, ProgramConsumer programConsumer) throws Throwable { String keepRule = "-keep class java.time.*"; Path keepRuleFile = temp.newFile("keepRuleFile.txt").toPath(); Files.write(keepRuleFile, Collections.singletonList(keepRule), StandardCharsets.UTF_8); L8Command.Builder builder1 = - prepareBuilder(new TestDiagnosticMessagesImpl()) - .setProgramConsumer(DexIndexedConsumer.emptyConsumer()) + prepareBuilder(diagnostics) + .setProgramConsumer(programConsumer) .addDesugaredLibraryConfiguration( StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) .addProguardConfigurationFiles(keepRuleFile); @@ -222,6 +286,24 @@ } @Test + public void addProguardConfigurationFileDex() throws Throwable { + addProguardConfigurationFile( + new TestDiagnosticMessagesImpl(), DexIndexedConsumer.emptyConsumer()); + } + + @Test + public void addProguardConfigurationFileClassFile() throws Throwable { + TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl(); + try { + addProguardConfigurationFile(diagnostics, ClassFileConsumer.emptyConsumer()); + fail("Expected failure"); + } catch (CompilationFailedException e) { + diagnostics.assertErrorsMatch( + diagnosticMessage(containsString("not support shrinking when generating class files"))); + } + } + + @Test public void desugaredLibrary() throws CompilationFailedException { L8Command l8Command = parse("--desugared-lib", ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString());
diff --git a/src/test/java/com/android/tools/r8/SingleTestRunResult.java b/src/test/java/com/android/tools/r8/SingleTestRunResult.java index 4d72d22..c03c8e05 100644 --- a/src/test/java/com/android/tools/r8/SingleTestRunResult.java +++ b/src/test/java/com/android/tools/r8/SingleTestRunResult.java
@@ -118,6 +118,7 @@ return self(); } + @Override public RR disassemble() throws IOException, ExecutionException { return disassemble(System.out); }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java index 1bd188a..9aa9789 100644 --- a/src/test/java/com/android/tools/r8/TestBase.java +++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -120,7 +120,11 @@ public enum Backend { CF, - DEX + DEX; + + public static Backend fromConsumer(ProgramConsumer consumer) { + return consumer instanceof ClassFileConsumer ? CF : DEX; + } } public static R8FullTestBuilder testForR8(TemporaryFolder temp, Backend backend) {
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java index 6f6263a..43b5478 100644 --- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java +++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -300,6 +300,7 @@ public T setProgramConsumer(ProgramConsumer programConsumer) { assert programConsumer != null; + assert backend == Backend.fromConsumer(programConsumer); this.programConsumer = programConsumer; return self(); }
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java index 75b7336..06fd76e 100644 --- a/src/test/java/com/android/tools/r8/TestParameters.java +++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -4,9 +4,11 @@ package com.android.tools.r8; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.android.tools.r8.TestBase.Backend; import com.android.tools.r8.TestRuntime.NoneRuntime; +import com.android.tools.r8.ToolHelper.DexVm; import com.android.tools.r8.utils.AndroidApiLevel; // Actual test parameters for a specific configuration. Currently just the runtime configuration. @@ -76,4 +78,9 @@ public void assertNoneRuntime() { assertEquals(NoneRuntime.getInstance(), runtime); } + + public DexVm.Version getDexRuntimeVersion() { + assertTrue(isDexRuntime()); + return getRuntime().asDex().getVm().getVersion(); + } }
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java index 3069351..98881e9 100644 --- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java +++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -10,6 +10,8 @@ import com.android.tools.r8.references.TypeReference; import com.android.tools.r8.shaking.ProguardKeepAttributes; import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.FileUtils; +import com.android.tools.r8.utils.StringUtils; import java.io.IOException; import java.nio.file.Path; import java.util.Arrays; @@ -75,6 +77,12 @@ return minification(false); } + public T addClassObfuscationDictionary(String... names) throws IOException { + Path path = getState().getNewTempFolder().resolve("classobfuscationdictionary.txt"); + FileUtils.writeTextFile(path, StringUtils.join(" ", names)); + return addKeepRules("-classobfuscationdictionary " + path.toString()); + } + public abstract T addDataEntryResources(DataEntryResource... resources); public abstract T addKeepRuleFiles(List<Path> files);
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java index 3efb9b1..11bf740 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java
@@ -10,17 +10,32 @@ import static org.hamcrest.MatcherAssert.assertThat; 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.android.tools.r8.utils.codeinspector.FieldSubject; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; /** Tests that Proguard may change the visibility of a field or method that is explicitly kept. */ +@RunWith(Parameterized.class) public class AccessRelaxationProguardCompatTest extends TestBase { private static Class<?> clazz = AccessRelaxationProguardCompatTestClass.class; private static Class<?> clazzWithGetter = TestClassWithGetter.class; + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + public AccessRelaxationProguardCompatTest(TestParameters parameters) { + parameters.assertNoneRuntime(); + } + @Test public void r8Test() throws Exception { testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java index 8c2adf3..209aa18 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java
@@ -6,37 +6,46 @@ import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import com.android.tools.r8.R8Command; -import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.R8TestRunResult; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper.DexVm.Version; -import com.android.tools.r8.ToolHelper.ProcessResult; -import com.android.tools.r8.VmTestRunner; import com.android.tools.r8.code.InvokeDirect; import com.android.tools.r8.code.InvokeVirtual; import com.android.tools.r8.graph.DexCode; import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.origin.Origin; import com.android.tools.r8.smali.SmaliBuilder; import com.android.tools.r8.smali.SmaliBuilder.MethodSignature; import com.android.tools.r8.smali.SmaliTestBase; -import com.android.tools.r8.utils.AndroidApp; 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 java.util.function.Consumer; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; -@RunWith(VmTestRunner.class) +@RunWith(Parameterized.class) public class InvokeTypeConversionTest extends SmaliTestBase { + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withDexRuntimes().withAllApiLevels().build(); + } + private final String CLASS_NAME = "Example"; private MethodSignature main; + private final TestParameters parameters; + + public InvokeTypeConversionTest(TestParameters parameters) { + this.parameters = parameters; + } + private SmaliBuilder buildTestClass(String invokeLine) { SmaliBuilder builder = new SmaliBuilder(CLASS_NAME); builder.addDefaultConstructor(); @@ -63,29 +72,23 @@ SmaliBuilder builder, String expectedException, Consumer<CodeInspector> inspectorConsumer) throws Exception { - AndroidApp app = buildApplication(builder); - List<String> pgConfigs = - ImmutableList.of( - keepMainProguardConfiguration(CLASS_NAME), - // We're testing lens-based invocation type conversions. - "-dontoptimize", - "-dontobfuscate", - "-allowaccessmodification"); - R8Command.Builder command = ToolHelper.prepareR8CommandBuilder(app); - command.addProguardConfiguration(pgConfigs, Origin.unknown()); - AndroidApp processedApp = ToolHelper.runR8(command.build(), o -> { - o.enableInlining = false; - }); - ProcessResult artResult = runOnArtRaw(processedApp, CLASS_NAME); + R8TestRunResult result = + testForR8(parameters.getBackend()) + .addProgramDexFileData(builder.compile()) + .addKeepMainRule(CLASS_NAME) + .addKeepRules( + // We're testing lens-based invocation type conversions. + "-dontoptimize", "-dontobfuscate", "-allowaccessmodification") + .addOptionsModification(o -> o.enableInlining = false) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), CLASS_NAME); if (expectedException == null) { - assertEquals(0, artResult.exitCode); - assertEquals("0", artResult.stdout); + result.assertSuccessWithOutput("0"); + result.inspect(inspectorConsumer::accept); } else { - assertEquals(1, artResult.exitCode); - assertThat(artResult.stderr, containsString(expectedException)); + result.assertFailureWithErrorThatMatches(containsString(expectedException)); + result.inspectFailure(inspectorConsumer::accept); } - CodeInspector inspector = new CodeInspector(processedApp); - inspectorConsumer.accept(inspector); } // The following test checks invoke-direct, which refers to the private static method, is *not* @@ -105,8 +108,9 @@ SmaliBuilder builder = buildTestClass( "invoke-direct { v1 }, L" + CLASS_NAME + ";->bar()I"); String expectedError = - ToolHelper.getDexVm().getVersion().isOlderThanOrEqual(Version.V4_4_4) - ? "VerifyError" : "IncompatibleClassChangeError"; + parameters.getRuntime().asDex().getVm().getVersion().isOlderThanOrEqual(Version.V4_4_4) + ? "VerifyError" + : "IncompatibleClassChangeError"; run(builder, expectedError, dexInspector -> { ClassSubject clazz = dexInspector.clazz(CLASS_NAME); assertThat(clazz, isPresent());
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java index 164259f..e190074 100644 --- a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java +++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java
@@ -28,6 +28,7 @@ import java.util.Calendar; import java.util.List; import java.util.TreeSet; +import java.util.function.Consumer; public abstract class MethodGenerationBase extends TestBase { @@ -74,17 +75,18 @@ } // Running this method will regenerate / overwrite the content of the generated class. - protected void generateMethodsAndWriteThemToFile() throws IOException { - FileUtils.writeToFile(getGeneratedFile(), null, generateMethods().getBytes()); + protected void generateMethodsAndWriteThemToFile(Consumer<InternalOptions> optionsConsumer) + throws IOException { + FileUtils.writeToFile(getGeneratedFile(), null, generateMethods(optionsConsumer).getBytes()); } // Running this method generate the content of the generated class but does not overwrite it. - protected String generateMethods() throws IOException { + protected String generateMethods(Consumer<InternalOptions> optionsConsumer) throws IOException { CfCodePrinter codePrinter = new CfCodePrinter(); File tempFile = File.createTempFile("output-", ".java"); - readMethodTemplatesInto(codePrinter); + readMethodTemplatesInto(codePrinter, optionsConsumer); generateRawOutput(codePrinter, tempFile.toPath()); String result = formatRawOutput(tempFile.toPath()); @@ -92,8 +94,10 @@ return result; } - private void readMethodTemplatesInto(CfCodePrinter codePrinter) throws IOException { + private void readMethodTemplatesInto( + CfCodePrinter codePrinter, Consumer<InternalOptions> optionsConsumer) throws IOException { InternalOptions options = new InternalOptions(); + optionsConsumer.accept(options); JarClassFileReader reader = new JarClassFileReader( new JarApplicationReader(options),
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java new file mode 100644 index 0000000..745fc26 --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java
@@ -0,0 +1,75 @@ +// 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 com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestParameters; +import org.junit.Test; + +public class ClassesDistinguishedByDirectCheckCastTest extends HorizontalClassMergingTestBase { + public ClassesDistinguishedByDirectCheckCastTest( + 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("fail", "bar") + .inspect( + codeInspector -> { + // The two classes should not be merged. + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), isPresent()); + }); + } + + @NeverClassInline + public static class A { + @NeverInline + public void foo() { + System.out.println("foo"); + } + } + + @NeverClassInline + public static class B { + @NeverInline + public void bar() { + System.out.println("bar"); + } + } + + public static class Main { + @NeverInline + public static void checkObject(Object o) { + try { + B b = (B) o; + b.bar(); + } catch (ClassCastException ex) { + System.out.println("fail"); + } + } + + public static void main(String[] args) { + A a = new A(); + B b = new B(); + checkObject(a); + checkObject(b); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java new file mode 100644 index 0000000..6a61d2f --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java
@@ -0,0 +1,74 @@ +// 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 com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestParameters; +import org.junit.Test; + +public class ClassesDistinguishedByDirectInstanceOfTest extends HorizontalClassMergingTestBase { + public ClassesDistinguishedByDirectInstanceOfTest( + 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("foo", "bar", "false", "true") + .inspect( + codeInspector -> { + // The two classes should not be merged. + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), isPresent()); + }); + } + + @NeverClassInline + public static class A { + @NeverInline + public void foo() { + System.out.println("foo"); + } + } + + @NeverClassInline + public static class B { + public B(String a) {} + + @NeverInline + public void bar() { + System.out.println("bar"); + } + } + + public static class Main { + @NeverInline + public static void checkObject(Object o) { + System.out.println(o instanceof B); + } + + public static void main(String[] args) { + A a = new A(); + a.foo(); + B b = new B("hello"); + b.bar(); + checkObject(a); + checkObject(b); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java new file mode 100644 index 0000000..edd84cb --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
@@ -0,0 +1,84 @@ +// 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 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 ClassesDistinguishedByIndirectCheckCastToInterfaceTest + extends HorizontalClassMergingTestBase { + public ClassesDistinguishedByIndirectCheckCastToInterfaceTest( + 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) + .enableMergeAnnotations() + .enableInliningAnnotations() + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("fail", "bar") + .inspect( + codeInspector -> { + // The two classes should not be merged. + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), isPresent()); + }); + } + + @NeverMerge + @NeverClassInline + public interface I { + void bar(); + } + + @NeverClassInline + public static class A { + @NeverInline + public void foo() { + System.out.println("foo"); + } + } + + @NeverClassInline + public static class B implements I { + @NeverInline + public void bar() { + System.out.println("bar"); + } + } + + public static class Main { + @NeverInline + public static void checkObject(Object o) { + try { + I b = (I) o; + b.bar(); + } catch (ClassCastException ex) { + System.out.println("fail"); + } + } + + public static void main(String[] args) { + A a = new A(); + B b = new B(); + checkObject(a); + checkObject(b); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java new file mode 100644 index 0000000..c6f58af --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
@@ -0,0 +1,79 @@ +// 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 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 ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast + extends HorizontalClassMergingTestBase { + public ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast( + 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() + .enableMergeAnnotations() + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("false", "true") + .inspect( + codeInspector -> { + // The two classes should not be merged. + assertThat(codeInspector.clazz(A.class), isPresent()); + assertThat(codeInspector.clazz(B.class), isPresent()); + }); + } + + @NeverClassInline + @NeverMerge + public interface I { + void bar(); + } + + @NeverClassInline + public static class A { + @NeverInline + public void foo() { + System.out.println("foo"); + } + } + + @NeverClassInline + public static class B implements I { + @NeverInline + public void bar() { + System.out.println("bar"); + } + } + + public static class Main { + @NeverInline + public static void checkObject(Object o) { + System.out.println(o instanceof I); + } + + public static void main(String[] args) { + A a = new A(); + B b = new B(); + checkObject(a); + checkObject(b); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java new file mode 100644 index 0000000..b1d77c2 --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java
@@ -0,0 +1,64 @@ +// 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.TestParameters; +import org.junit.Test; + +public class ConstructorMergingTest extends HorizontalClassMergingTestBase { + public ConstructorMergingTest(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) + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("foo", "bar") + .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 A { + public A() { + System.out.println("foo"); + } + } + + @NeverClassInline + public static class B { + public B() { + System.out.println("bar"); + } + } + + public static class Main { + public static void main(String[] args) { + A a = new A(); + B b = new B(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java new file mode 100644 index 0000000..a1b2d1a --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java
@@ -0,0 +1,65 @@ +// 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.TestParameters; +import org.junit.Test; + +public class ConstructorMergingWithArgumentsTest extends HorizontalClassMergingTestBase { + public ConstructorMergingWithArgumentsTest( + 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) + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("foo hello", "bar world") + .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 A { + public A(String arg) { + System.out.println("foo " + arg); + } + } + + @NeverClassInline + public static class B { + public B(String arg) { + 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"); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/EmptyClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java similarity index 70% rename from src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/EmptyClassTest.java rename to src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java index e0d9a33..ffdae33 100644 --- a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/EmptyClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java
@@ -2,41 +2,25 @@ // 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; +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.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.BooleanUtils; -import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(Parameterized.class) -public class EmptyClassTest extends TestBase { - private final TestParameters parameters; - private final boolean enableHorizontalClassMerging; - +public class EmptyClassTest extends HorizontalClassMergingTestBase { public EmptyClassTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - this.parameters = parameters; - this.enableHorizontalClassMerging = enableHorizontalClassMerging; - } - - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + super(parameters, enableHorizontalClassMerging); } @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addInnerClasses(EmptyClassTest.class) + .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addOptionsModification( options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java new file mode 100644 index 0000000..72e016b --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java
@@ -0,0 +1,30 @@ +// 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 com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.BooleanUtils; +import java.util.List; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public abstract class HorizontalClassMergingTestBase extends TestBase { + protected final TestParameters parameters; + protected final boolean enableHorizontalClassMerging; + + protected HorizontalClassMergingTestBase( + TestParameters parameters, boolean enableHorizontalClassMerging) { + this.parameters = parameters; + this.enableHorizontalClassMerging = enableHorizontalClassMerging; + } + + @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/IdenticalFieldMembersTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java similarity index 74% rename from src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/IdenticalFieldMembersTest.java rename to src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java index 7935860..1cb2d2d 100644 --- a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/IdenticalFieldMembersTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java
@@ -2,39 +2,24 @@ // 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; +package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.*; -import com.android.tools.r8.utils.BooleanUtils; -import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(Parameterized.class) -public class IdenticalFieldMembersTest extends TestBase { - private final TestParameters parameters; - private final boolean enableHorizontalClassMerging; - +public class IdenticalFieldMembersTest extends HorizontalClassMergingTestBase { public IdenticalFieldMembersTest( TestParameters parameters, boolean enableHorizontalClassMerging) { - this.parameters = parameters; - this.enableHorizontalClassMerging = enableHorizontalClassMerging; - } - - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + super(parameters, enableHorizontalClassMerging); } @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addInnerClasses(IdenticalFieldMembersTest.class) + .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addOptionsModification( options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
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 new file mode 100644 index 0000000..226af98 --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
@@ -0,0 +1,79 @@ +// 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.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 org.junit.Test; + +public class MergedConstructorForwardingTest extends HorizontalClassMergingTestBase { + + public MergedConstructorForwardingTest( + 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) + .enableNeverClassInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("42", "13", "21", "39") + .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 A { + public A() { + this(42); + } + + public A(long x) { + System.out.println(x); + } + } + + @NeverClassInline + public static class B { + public B() { + this(7); + } + + public B(long y) { + System.out.println(y * 3); + } + } + + public static class Main { + public static void main(String[] args) { + A a = new A(); + a = new A(13); + B b = new B(); + b = new B(13); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/NoOverlappingConstructorsPolicyTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java similarity index 65% rename from src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/NoOverlappingConstructorsPolicyTest.java rename to src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java index e646087..fbd587d 100644 --- a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/NoOverlappingConstructorsPolicyTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java
@@ -2,45 +2,27 @@ // 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; +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.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.shaking.horizontalclassmerging.EmptyClassTest.A; -import com.android.tools.r8.shaking.horizontalclassmerging.EmptyClassTest.B; -import com.android.tools.r8.shaking.horizontalclassmerging.EmptyClassTest.Main; -import com.android.tools.r8.utils.BooleanUtils; -import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(Parameterized.class) -public class NoOverlappingConstructorsPolicyTest extends TestBase { - private final TestParameters parameters; - private final boolean enableHorizontalClassMerging; +public class OverlappingConstructorsTest extends HorizontalClassMergingTestBase { - public NoOverlappingConstructorsPolicyTest( + public OverlappingConstructorsTest( TestParameters parameters, boolean enableHorizontalClassMerging) { - this.parameters = parameters; - this.enableHorizontalClassMerging = enableHorizontalClassMerging; - } - - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + super(parameters, enableHorizontalClassMerging); } @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addInnerClasses(this.getClass()) + .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addOptionsModification( options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging) @@ -51,7 +33,7 @@ codeInspector -> { if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); + assertThat(codeInspector.clazz(B.class), not(isPresent())); assertThat(codeInspector.clazz(C.class), not(isPresent())); // TODO(b/165517236): Explicitly check classes have been merged. } else {
diff --git a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/RemapMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java similarity index 73% rename from src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/RemapMethodTest.java rename to src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java index 97df366..f0814bd 100644 --- a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/RemapMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java
@@ -2,7 +2,7 @@ // 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; +package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; @@ -10,46 +10,29 @@ import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; -import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.BooleanUtils; -import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(Parameterized.class) -public class RemapMethodTest extends TestBase { - private final TestParameters parameters; - private final boolean enableHorizontalClassMerging; - +public class RemapMethodTest extends HorizontalClassMergingTestBase { public RemapMethodTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - this.parameters = parameters; - this.enableHorizontalClassMerging = enableHorizontalClassMerging; - } - - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + super(parameters, enableHorizontalClassMerging); } @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addInnerClasses(this.getClass()) + .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addOptionsModification( options -> { options.enableHorizontalClassMerging = enableHorizontalClassMerging; - options.enableVerticalClassMerging = false; }) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .compile() - // .run(parameters.getRuntime(), Main.class) - // .assertSuccessWithOutputLines("foo", "foo", "bar", "bar") + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("foo", "foo", "bar", "bar") .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java new file mode 100644 index 0000000..59ea0b2 --- /dev/null +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java
@@ -0,0 +1,78 @@ +// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.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 SyntheticConstructorArgumentsMerged extends HorizontalClassMergingTestBase { + public SyntheticConstructorArgumentsMerged( + 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()) + .compile() + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("5", "42") + .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 A { + public A(B b) { + b.print(42); + } + } + + @NeverClassInline + public static class B { + public B(B b) { + if (b != null) { + b.print(5); + } + } + + @NeverInline + void print(int v) { + System.out.println(v); + } + } + + public static class Main { + public static void main(String[] args) { + B b = new B(null); + B b1 = new B(b); + A a = new A(b); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/VirtualMethodNotOverlappingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodNotOverlappingTest.java similarity index 72% rename from src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/VirtualMethodNotOverlappingTest.java rename to src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodNotOverlappingTest.java index 711f217..c80c1ef 100644 --- a/src/test/java/com/android/tools/r8/shaking/horizontalclassmerging/VirtualMethodNotOverlappingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodNotOverlappingTest.java
@@ -2,40 +2,25 @@ // 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; +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.*; -import com.android.tools.r8.utils.BooleanUtils; -import java.util.*; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(Parameterized.class) -public class VirtualMethodNotOverlappingTest extends TestBase { - private final TestParameters parameters; - private final boolean enableHorizontalClassMerging; - +public class VirtualMethodNotOverlappingTest extends HorizontalClassMergingTestBase { public VirtualMethodNotOverlappingTest( TestParameters parameters, boolean enableHorizontalClassMerging) { - this.parameters = parameters; - this.enableHorizontalClassMerging = enableHorizontalClassMerging; - } - - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + super(parameters, enableHorizontalClassMerging); } @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addInnerClasses(VirtualMethodNotOverlappingTest.class) + .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addOptionsModification( options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
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 e42f33d..db4d3df 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
@@ -5,11 +5,18 @@ package com.android.tools.r8.desugar.desugaredlibrary; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import com.android.tools.r8.CompilationMode; +import com.android.tools.r8.L8Command; import com.android.tools.r8.NeverInline; +import com.android.tools.r8.OutputMode; +import com.android.tools.r8.StringResource; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestRunResult; +import com.android.tools.r8.ToolHelper; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.BooleanUtils; @@ -27,6 +34,7 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -51,8 +59,8 @@ return buildParameters( BooleanUtils.values(), getTestParameters() - .withDexRuntimes() - .withAllApiLevels() + .withAllRuntimes() + .withAllApiLevelsAlsoForCf() .withApiLevel(AndroidApiLevel.N) .build()); } @@ -126,30 +134,62 @@ .inspect(this::checkRewrittenInvokes) .writeToZip(); - // Collection keep rules is only implemented in the DEX writer. - String desugaredLibraryKeepRules = keepRuleConsumer.get(); - if (desugaredLibraryKeepRules != null) { - assertEquals(0, desugaredLibraryKeepRules.length()); - desugaredLibraryKeepRules = "-keep class * { *; }"; - } + if (parameters.getRuntime().isDex()) { + // Collection keep rules is only implemented in the DEX writer. + String desugaredLibraryKeepRules = keepRuleConsumer.get(); + if (desugaredLibraryKeepRules != null) { + assertEquals(0, desugaredLibraryKeepRules.length()); + desugaredLibraryKeepRules = "-keep class * { *; }"; + } - // Convert to DEX without desugaring. - testForD8() - .addProgramFiles(jar) - .setMinApi(parameters.getApiLevel()) - .disableDesugaring() - .compile() - .addDesugaredCoreLibraryRunClassPath( - this::buildDesugaredLibrary, - parameters.getApiLevel(), - desugaredLibraryKeepRules, - shrinkDesugaredLibrary) - .run(parameters.getRuntime(), TestClass.class) - .assertSuccessWithOutput(expectedOutput); + // Convert to DEX without desugaring and run. + testForD8() + .addProgramFiles(jar) + .setMinApi(parameters.getApiLevel()) + .disableDesugaring() + .compile() + .addDesugaredCoreLibraryRunClassPath( + this::buildDesugaredLibrary, + parameters.getApiLevel(), + desugaredLibraryKeepRules, + shrinkDesugaredLibrary) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(expectedOutput); + } else { + // Build the desugared library in class file format. + Path desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs.jar"); + L8Command.Builder l8Builder = + L8Command.builder() + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) + .addProgramFiles(ToolHelper.getDesugarJDKLibs()) + .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS) + .setMode(CompilationMode.DEBUG) + .addDesugaredLibraryConfiguration( + StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) + .setMinApiLevel(parameters.getApiLevel().getLevel()) + .setOutput(desugaredLib, OutputMode.ClassFile); + ToolHelper.runL8(l8Builder.build()); + + // Run on the JVM with desuagred library on classpath. + TestRunResult result = + testForJvm() + .addProgramFiles(jar) + .addRunClasspathFiles(desugaredLib) + .run(parameters.getRuntime(), TestClass.class); + if (parameters.getApiLevel().isGreaterThan(AndroidApiLevel.N_MR1)) { + // java.time is present from O, so the desugared library classes are not loaded. + result.assertSuccessWithOutput(expectedOutput); + } else { + // TODO(b/164396438): Produce correct stack map. + result.assertFailureWithErrorThatMatches( + containsString("java.lang.VerifyError: Bad type on operand stack")); + } + } } @Test public void testTimeD8() throws Exception { + Assume.assumeTrue(parameters.getRuntime().isDex()); KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); testForD8() .addInnerClasses(JavaTimeTest.class) @@ -168,6 +208,7 @@ @Test public void testTimeR8() throws Exception { + Assume.assumeTrue(parameters.getRuntime().isDex()); KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); testForR8(parameters.getBackend()) .addInnerClasses(JavaTimeTest.class)
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 2275a44..2b84919 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
@@ -66,7 +66,6 @@ } private Path buildSplitDesugaredLibraryPart2() throws Exception { - Path outputCf = temp.newFolder().toPath().resolve("merger-input-split-cf.zip"); Path outputDex = temp.newFolder().toPath().resolve("merger-input-split-dex.zip"); L8.run( L8Command.builder() @@ -76,13 +75,8 @@ .addDesugaredLibraryConfiguration( StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING)) .setMinApiLevel(AndroidApiLevel.B.getLevel()) - .setOutput(outputCf, OutputMode.DexIndexed) + .setOutput(outputDex, OutputMode.DexIndexed) .build()); - testForD8() - .addProgramFiles(outputCf) - .setMinApi(AndroidApiLevel.B) - .compile() - .writeToZip(outputDex); return outputDex; } }
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java b/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java index 186b01b..cb0da77 100644 --- a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java +++ b/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
@@ -8,26 +8,74 @@ import com.android.tools.r8.DesugarGraphConsumer; import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.utils.StringUtils; +import com.android.tools.r8.utils.StringUtils.BraceType; +import com.android.tools.r8.utils.WorkList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Function; public class DesugarGraphTestConsumer implements DesugarGraphConsumer { private boolean finished = false; - private Map<Origin, Set<Origin>> edges = new HashMap<>(); + + // Map from a dependency to its immediate dependents. + private final Map<Origin, Set<Origin>> dependents = new HashMap<>(); + + // Map from a dependent to its immedate dependencies. + private Map<Origin, Set<Origin>> dependencies = null; + + @Override + public String toString() { + if (dependents.isEmpty()) { + return "<empty>"; + } + StringBuilder builder = new StringBuilder(); + dependents.forEach( + (k, vs) -> + StringUtils.append(builder.append(k).append(" -> "), vs, ", ", BraceType.TUBORG) + .append("\n")); + return builder.toString(); + } + + public Set<Origin> getDirectDependencies(Origin dependent) { + return Collections.unmodifiableSet( + dependencies.getOrDefault(dependent, Collections.emptySet())); + } + + public Set<Origin> getDirectDependents(Origin dependency) { + return Collections.unmodifiableSet(dependents.getOrDefault(dependency, Collections.emptySet())); + } + + public Set<Origin> getTransitiveDependencies(Origin dependent) { + return getTransitiveClosure(dependent, this::getDirectDependencies); + } + + public Set<Origin> getTransitiveDependents(Origin dependency) { + return getTransitiveClosure(dependency, this::getDirectDependents); + } + + private static Set<Origin> getTransitiveClosure( + Origin item, Function<Origin, Set<Origin>> edges) { + WorkList<Origin> worklist = WorkList.newEqualityWorkList(edges.apply(item)); + while (worklist.hasNext()) { + worklist.addIfNotSeen(edges.apply(worklist.next())); + } + return worklist.getSeenSet(); + } public boolean contains(Origin dependency, Origin dependent) { assertTrue(finished); - return edges.getOrDefault(dependency, Collections.emptySet()).contains(dependent); + return dependents.getOrDefault(dependency, Collections.emptySet()).contains(dependent); } public int totalEdgeCount() { assertTrue(finished); int count = 0; - for (Set<Origin> dependents : edges.values()) { + for (Set<Origin> dependents : dependents.values()) { count += dependents.size(); } return count; @@ -36,12 +84,18 @@ @Override public synchronized void accept(Origin dependent, Origin dependency) { assertFalse(finished); - edges.computeIfAbsent(dependency, s -> new HashSet<>()).add(dependent); + dependents.computeIfAbsent(dependency, s -> new HashSet<>()).add(dependent); } @Override public void finished() { assertFalse(finished); finished = true; + dependencies = new HashMap<>(); + dependents.forEach( + (dependency, dependents) -> + dependents.forEach( + dependent -> + dependencies.computeIfAbsent(dependent, k -> new HashSet<>()).add(dependency))); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphUtils.java b/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphUtils.java index 937540e..480f81d 100644 --- a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphUtils.java +++ b/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphUtils.java
@@ -3,10 +3,18 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.desugar.graph; +import com.android.tools.r8.ClassFileResourceProvider; import com.android.tools.r8.D8TestBuilder; +import com.android.tools.r8.ProgramResource; +import com.android.tools.r8.ProgramResource.Kind; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.utils.DescriptorUtils; import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; public class DesugarGraphUtils { @@ -21,6 +29,8 @@ return origin; } + private final Map<String, Origin> origins = new HashMap<>(); + private static Origin makeOrigin(String name) { return new Origin(Origin.root()) { @Override @@ -29,4 +39,46 @@ } }; } + + public Origin origin(String typeName) { + return origins.computeIfAbsent(typeName, DesugarGraphUtils::makeOrigin); + } + + public Origin origin(Class<?> clazz) { + return origin(clazz.getTypeName()); + } + + public void addProgramClasses(D8TestBuilder builder, Class<?>... classes) throws IOException { + for (Class<?> clazz : classes) { + builder.getBuilder().addClassProgramData(ToolHelper.getClassAsBytes(clazz), origin(clazz)); + } + } + + public void addClasspathClass(D8TestBuilder builder, Class<?>... classes) throws IOException { + Map<String, ProgramResource> map = new HashMap<>(); + for (Class<?> clazz : classes) { + String descriptor = DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()); + map.put( + descriptor, + ProgramResource.fromBytes( + origin(clazz), + Kind.CF, + ToolHelper.getClassAsBytes(clazz), + Collections.singleton(descriptor))); + } + builder + .getBuilder() + .addClasspathResourceProvider( + new ClassFileResourceProvider() { + @Override + public Set<String> getClassDescriptors() { + return map.keySet(); + } + + @Override + public ProgramResource getProgramResource(String descriptor) { + return map.get(descriptor); + } + }); + } }
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java b/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java new file mode 100644 index 0000000..650338c --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
@@ -0,0 +1,74 @@ +// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.desugar.graph; + +import static org.junit.Assert.assertEquals; + +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.google.common.collect.ImmutableSet; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class Regress167562221Test extends TestBase { + + // Classpath classes: + + public interface I {} + + public interface J extends I {} + + // Does not contribute to C so won't be in any edges. + public interface K extends I {} + + public static class A implements J {} + + // Does not contribute to C so won't be in any edges. + public static class B implements K {} + + // Program class: + + public static class C extends A {} + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + public Regress167562221Test(TestParameters parameters) { + parameters.assertNoneRuntime(); + } + + @Test + public void repro() throws Throwable { + DesugarGraphUtils utils = new DesugarGraphUtils(); + DesugarGraphTestConsumer consumer = new DesugarGraphTestConsumer(); + testForD8() + .apply(b -> b.getBuilder().setDesugarGraphConsumer(consumer)) + .apply(b -> utils.addClasspathClass(b, I.class, J.class, K.class, A.class, B.class)) + .apply(b -> utils.addProgramClasses(b, C.class)) + .setMinApi(AndroidApiLevel.B) + .compile(); + + assertEquals( + ImmutableSet.of(utils.origin(A.class)), + consumer.getDirectDependencies(utils.origin(C.class))); + + assertEquals( + ImmutableSet.of(utils.origin(A.class), utils.origin(J.class), utils.origin(I.class)), + consumer.getTransitiveDependencies(utils.origin(C.class))); + + // Check that the unrelated CP types are not in the graph. + + assertEquals(ImmutableSet.of(), consumer.getTransitiveDependencies(utils.origin(K.class))); + assertEquals(ImmutableSet.of(), consumer.getTransitiveDependencies(utils.origin(B.class))); + + assertEquals(ImmutableSet.of(), consumer.getTransitiveDependents(utils.origin(K.class))); + assertEquals(ImmutableSet.of(), consumer.getTransitiveDependents(utils.origin(B.class))); + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MissingMethodTest.java b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MissingMethodTest.java index 4106cd58..f147d3b 100644 --- a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MissingMethodTest.java +++ b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MissingMethodTest.java
@@ -3,15 +3,58 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.desugar.staticinterfacemethod; -import com.android.tools.r8.AsmTestBase; -import org.junit.Ignore; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRunResult; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; -public class MissingMethodTest extends AsmTestBase { +@RunWith(Parameterized.class) +public class MissingMethodTest extends TestBase { - @Ignore("b/69835274") + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + private final TestParameters parameters; + + public MissingMethodTest(TestParameters parameters) { + this.parameters = parameters; + } + @Test - public void testDesugarInvokeMissingMethod() throws Exception { - ensureException("Main", NoSuchMethodError.class, InterfaceDump.dump(), MainDump.dump()); + public void testReference() throws Exception { + TestRunResult<?> result = + testForRuntime(parameters) + .addProgramClassFileData(InterfaceDump.dump(), MainDump.dump()) + .run(parameters.getRuntime(), "Main"); + if (parameters.isDexRuntime() + && parameters.getApiLevel().isLessThan(apiLevelWithStaticInterfaceMethodsSupport())) { + // TODO(b/69835274): Desugaring should preserve exception. + result.assertFailureWithErrorThatThrows(NoClassDefFoundError.class); + } else { + result.assertFailureWithErrorThatThrows(NoSuchMethodError.class); + } + } + + @Test + public void testR8() throws Exception { + TestRunResult<?> result = + testForR8(parameters.getBackend()) + .addProgramClassFileData(InterfaceDump.dump(), MainDump.dump()) + .addKeepMainRule("Main") + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), "Main"); + if (parameters.isDexRuntime() + && parameters.getApiLevel().isLessThan(apiLevelWithStaticInterfaceMethodsSupport())) { + // TODO(b/69835274): Desugaring should preserve exception. + result.assertFailureWithErrorThatThrows(NoClassDefFoundError.class); + } else { + result.assertFailureWithErrorThatThrows(NoSuchMethodError.class); + } } }
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 49e7256..5cb94de 100644 --- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java +++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -9,6 +9,8 @@ import com.android.tools.r8.code.ConstString; import com.android.tools.r8.code.Instruction; import com.android.tools.r8.code.ReturnVoid; +import com.android.tools.r8.graph.AppInfo; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexApplication; @@ -152,7 +154,7 @@ ApplicationWriter writer = new ApplicationWriter( application, - null, + AppView.createForD8(AppInfo.createInitialAppInfo(application)), options, null, GraphLens.getIdentityLens(),
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ClassAccessEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ClassAccessEnumUnboxingTest.java new file mode 100644 index 0000000..a39e30f --- /dev/null +++ b/src/test/java/com/android/tools/r8/enumunboxing/ClassAccessEnumUnboxingTest.java
@@ -0,0 +1,155 @@ +// 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.Assume; +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 ClassAccessEnumUnboxingTest 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 ClassAccessEnumUnboxingTest( + TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) { + this.parameters = parameters; + this.enumValueOptimization = enumValueOptimization; + this.enumKeepRules = enumKeepRules; + } + + @Test + public void testEnumUnboxing() throws Exception { + Assume.assumeTrue("studio rules required to use valueOf", enumKeepRules.isStudio()); + R8TestRunResult run = + testForR8(parameters.getBackend()) + .addInnerClasses(ClassAccessEnumUnboxingTest.class) + .addKeepMainRule(Main.class) + .addKeepRules(enumKeepRules.getKeepRules()) + .enableNeverClassInliningAnnotations() + .enableInliningAnnotations() + .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) + .allowDiagnosticInfoMessages() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspectDiagnosticMessages( + m -> { + assertEnumIsUnboxed(ProtoEnumLike.class, ProtoEnumLike.class.getSimpleName(), m); + assertEnumIsUnboxed(UnboxableEnum.class, UnboxableEnum.class.getSimpleName(), m); + assertEnumIsBoxed(EscapingEnum1.class, EscapingEnum1.class.getSimpleName(), m); + assertEnumIsBoxed(EscapingEnum2.class, EscapingEnum2.class.getSimpleName(), m); + }) + .run(parameters.getRuntime(), Main.class) + .assertSuccess(); + assertLines2By2Correct(run.getStdOut()); + } + + @NeverClassInline + enum ProtoEnumLike { + A, + B, + C; + + @Override + @NeverInline + public String toString() { + return "an instance of " + this.getClass().getName(); + } + } + + @NeverClassInline + enum UnboxableEnum { + A, + B, + C; + + @Override + @NeverInline + public String toString() { + return "an instance of " + + this.getClass().getName() + + this.getClass().getSimpleName() + + this.getClass().getCanonicalName(); + } + } + + @NeverClassInline + enum EscapingEnum1 { + A, + B, + C; + } + + @NeverClassInline + enum EscapingEnum2 { + A, + B, + C; + } + + static class Main { + + public static void main(String[] args) { + unboxableProtoCase(); + unboxableCase(); + nonUnboxableCase(); + } + + @NeverInline + private static void unboxableCase() { + System.out.println(UnboxableEnum.A.ordinal()); + System.out.println(0); + System.out.println(UnboxableEnum.A.toString()); + System.out.println("an instance of intintint"); + } + + @NeverInline + private static void unboxableProtoCase() { + System.out.println(ProtoEnumLike.A.ordinal()); + System.out.println(0); + System.out.println(ProtoEnumLike.A.toString()); + System.out.println("an instance of int"); + } + + @NeverInline + private static void nonUnboxableCase() { + System.out.println(EscapingEnum1.A.ordinal()); + System.out.println(0); + System.out.println(EscapingEnum2.A.ordinal()); + System.out.println(0); + System.out.println(EscapingEnum1.B.ordinal()); + System.out.println(1); + System.out.println(EscapingEnum2.B.ordinal()); + System.out.println(1); + System.out.println(getEnum(EscapingEnum1.class, "A").ordinal()); + System.out.println(0); + System.out.println(getEnum(EscapingEnum2.class, "A").ordinal()); + System.out.println(0); + System.out.println(getEnum(EscapingEnum1.class, "B").ordinal()); + System.out.println(1); + System.out.println(getEnum(EscapingEnum2.class, "B").ordinal()); + System.out.println(1); + } + + @NeverInline + private static <T extends Enum<T>> Enum<T> getEnum(Class<T> enumClass, String value) { + return Enum.valueOf(enumClass, value); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingMethods.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingMethods.java index e1d51cc..cc2aa0c 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingMethods.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingMethods.java
@@ -51,4 +51,17 @@ } return unboxedEnum1 == unboxedEnum2; } + + // Methods zeroCheck and zeroCheckMessage are used to replace null checks on unboxed enums. + public static void zeroCheck(int unboxedEnum) { + if (unboxedEnum == 0) { + throw new NullPointerException(); + } + } + + public static void zeroCheckMessage(int unboxedEnum, String message) { + if (unboxedEnum == 0) { + throw new NullPointerException(message); + } + } }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/GenerateEnumUnboxingMethods.java b/src/test/java/com/android/tools/r8/enumunboxing/GenerateEnumUnboxingMethods.java index 706cdc7..4abe533 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/GenerateEnumUnboxingMethods.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/GenerateEnumUnboxingMethods.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.cfmethodgeneration.MethodGenerationBase; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.utils.FileUtils; +import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.ImmutableList; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -50,16 +51,22 @@ return METHOD_TEMPLATE_CLASSES; } + private static void setReadInputStackMap(InternalOptions options) { + options.testing.readInputStackMaps = true; + } + @Test public void testEnumUtilityMethodsGenerated() throws Exception { ArrayList<Class<?>> sorted = new ArrayList<>(getMethodTemplateClasses()); sorted.sort(Comparator.comparing(Class::getTypeName)); assertEquals("Classes should be listed in sorted order", sorted, getMethodTemplateClasses()); assertEquals( - FileUtils.readTextFile(getGeneratedFile(), StandardCharsets.UTF_8), generateMethods()); + FileUtils.readTextFile(getGeneratedFile(), StandardCharsets.UTF_8), + generateMethods(GenerateEnumUnboxingMethods::setReadInputStackMap)); } public static void main(String[] args) throws Exception { - new GenerateEnumUnboxingMethods(null).generateMethodsAndWriteThemToFile(); + new GenerateEnumUnboxingMethods(null) + .generateMethodsAndWriteThemToFile(GenerateEnumUnboxingMethods::setReadInputStackMap); } }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java index e91be2b..dc21961 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java
@@ -33,7 +33,7 @@ SuccessIntFieldOrdinal.class, SuccessIntFieldInitializerInit.class, SuccessStringField.class, - SuccessMultiConstructorIntField.class + SuccessMultiConstructorIntField.class, }; private final TestParameters parameters; @@ -71,7 +71,7 @@ testClass(compile, failure, true); } for (Class<?> success : SUCCESSES) { - testClass(compile, success, success != SuccessUnusedField.class); + testClass(compile, success, false); } } @@ -423,8 +423,7 @@ int field1; EnumField(int i0) { - this.field0 = i0; - this.field1 = -1; + this(i0, -1); } EnumField(int i0, int i1) {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/NullCheckEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/NullCheckEnumUnboxingTest.java new file mode 100644 index 0000000..25a3434 --- /dev/null +++ b/src/test/java/com/android/tools/r8/enumunboxing/NullCheckEnumUnboxingTest.java
@@ -0,0 +1,197 @@ +// 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 com.android.tools.r8.utils.AndroidApiLevel; +import java.util.List; +import java.util.Objects; +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 NullCheckEnumUnboxingTest 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 NullCheckEnumUnboxingTest( + TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) { + this.parameters = parameters; + this.enumValueOptimization = enumValueOptimization; + this.enumKeepRules = enumKeepRules; + } + + @Test + public void testEnumUnboxing() throws Exception { + R8TestRunResult run = + testForR8(parameters.getBackend()) + .addInnerClasses(NullCheckEnumUnboxingTest.class) + .addKeepMainRule(MainNullTest.class) + .addKeepRules(enumKeepRules.getKeepRules()) + .enableNeverClassInliningAnnotations() + .enableInliningAnnotations() + .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) + .allowDiagnosticMessages() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspectDiagnosticMessages( + m -> { + assertEnumIsUnboxed(MyEnum.class, MyEnum.class.getSimpleName(), m); + // MyEnum19 is unboxed only if minAPI > 19 because Objects#requiredNonNull is then + // present. + if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.K)) { + assertEnumIsUnboxed(MyEnum19.class, MyEnum19.class.getSimpleName(), m); + } else { + assertEnumIsBoxed(MyEnum19.class, MyEnum19.class.getSimpleName(), m); + } + }) + .run(parameters.getRuntime(), MainNullTest.class) + .assertSuccess(); + assertLines2By2Correct(run.getStdOut()); + } + + @NeverClassInline + enum MyEnum { + A, + B, + C + } + + @NeverClassInline + enum MyEnum19 { + A, + B, + C + } + + static class MainNullTest { + + public static void main(String[] args) { + nullCheckTests(); + nullCheckMessageTests(); + } + + private static void nullCheckTests() { + nullCheck0Test(MyEnum.A, false); + nullCheck0Test(MyEnum.B, false); + nullCheck0Test(null, true); + + nullCheck1Test(MyEnum.A, false); + nullCheck1Test(MyEnum.B, false); + nullCheck1Test(null, true); + + nullCheck2Test(MyEnum19.A, false); + nullCheck2Test(MyEnum19.B, false); + nullCheck2Test(null, true); + } + + private static void nullCheckMessageTests() { + nullCheckMessage0Test(MyEnum.A, "myMessageA", false); + nullCheckMessage0Test(MyEnum.B, "myMessageB", false); + nullCheckMessage0Test(null, "myMessageN", true); + + nullCheckMessage1Test(MyEnum19.A, "myMessageA", false); + nullCheckMessage1Test(MyEnum19.B, "myMessageB", false); + nullCheckMessage1Test(null, "myMessageN", true); + } + + private static void nullCheck0Test(MyEnum input, boolean isNull) { + String result = "pass"; + try { + nullCheck0(input); + } catch (NullPointerException ex8) { + result = "fail"; + } + System.out.println(result); + System.out.println(isNull ? "fail" : "pass"); + } + + private static void nullCheck1Test(MyEnum input, boolean isNull) { + String result = "pass"; + try { + nullCheck1(input); + } catch (NullPointerException ex8) { + result = "fail"; + } + System.out.println(result); + System.out.println(isNull ? "fail" : "pass"); + } + + private static void nullCheck2Test(MyEnum19 input, boolean isNull) { + String result = "pass"; + try { + nullCheck2(input); + } catch (NullPointerException ex) { + result = "fail"; + } + System.out.println(result); + System.out.println(isNull ? "fail" : "pass"); + } + + private static void nullCheckMessage0Test(MyEnum input, String message, boolean isNull) { + String result = "pass"; + try { + nullCheckMessage0(input, message); + } catch (NullPointerException ex) { + result = ex.getMessage(); + } + System.out.println(result); + System.out.println(isNull ? message : "pass"); + } + + private static void nullCheckMessage1Test(MyEnum19 input, String message, boolean isNull) { + String result = "pass"; + try { + nullCheckMessage1(input, message); + } catch (NullPointerException ex) { + result = ex.getMessage(); + } + System.out.println(result); + System.out.println(isNull ? message : "pass"); + } + + @NeverInline + private static void nullCheck0(MyEnum e) { + if (e == null) { + throw new NullPointerException(); + } + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @NeverInline + private static void nullCheck1(MyEnum e) { + e.getClass(); + } + + @NeverInline + private static void nullCheck2(MyEnum19 e) { + Objects.requireNonNull(e); + } + + @NeverInline + private static void nullCheckMessage0(MyEnum e, String message) { + if (e == null) { + throw new NullPointerException(message); + } + } + + @NeverInline + private static void nullCheckMessage1(MyEnum19 e, String message) { + Objects.requireNonNull(e, message); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java index 05c11c4..cd417d1 100644 --- a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java +++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.cfmethodgeneration.MethodGenerationBase; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.utils.FileUtils; +import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.ImmutableList; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -68,16 +69,22 @@ return METHOD_TEMPLATE_CLASSES; } + private static void setReadInputStackMap(InternalOptions options) { + options.testing.readInputStackMaps = true; + } + @Test public void testBackportsGenerated() throws Exception { ArrayList<Class<?>> sorted = new ArrayList<>(getMethodTemplateClasses()); sorted.sort(Comparator.comparing(Class::getTypeName)); assertEquals("Classes should be listed in sorted order", sorted, getMethodTemplateClasses()); assertEquals( - FileUtils.readTextFile(getGeneratedFile(), StandardCharsets.UTF_8), generateMethods()); + FileUtils.readTextFile(getGeneratedFile(), StandardCharsets.UTF_8), + generateMethods(GenerateBackportMethods::setReadInputStackMap)); } public static void main(String[] args) throws Exception { - new GenerateBackportMethods(null).generateMethodsAndWriteThemToFile(); + new GenerateBackportMethods(null) + .generateMethodsAndWriteThemToFile(GenerateBackportMethods::setReadInputStackMap); } }
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 e4e0b53..fdc2ab9 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -30,6 +30,7 @@ import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.DexFileOverflowDiagnostic; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.AppInfo; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.Code; @@ -866,7 +867,7 @@ ApplicationWriter writer = new ApplicationWriter( application, - null, + AppView.createForD8(AppInfo.createInitialAppInfo(application)), options, null, GraphLens.getIdentityLens(),
diff --git a/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java b/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java index adfbcec..8100e16 100644 --- a/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java +++ b/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.naming.arraytypes; -import static org.junit.Assume.assumeTrue; - import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; @@ -41,7 +39,7 @@ @Parameterized.Parameters(name = "{0}") public static TestParametersCollection data() { - return getTestParameters().withAllRuntimes().build(); + return getTestParameters().withAllRuntimesAndApiLevels().build(); } @BeforeClass @@ -75,7 +73,7 @@ .addProgramClassFileData(generateTestClass()) .addKeepMainRule(Main.class) .addKeepRules("-keep class " + generatedTestClassName + " { test(...); }") - .setMinApi(parameters.getRuntime()) + .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutput(expectedOutput); } @@ -106,20 +104,17 @@ .addKeepRules("-applymapping " + mappingFile.toAbsolutePath()) .noMinification() .noTreeShaking() - .setMinApi(parameters.getRuntime()) + .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutput(expectedOutput); } @Test - public void testD8() throws Exception { - assumeTrue(parameters.isDexRuntime()); - testForD8() + public void testRuntime() throws Exception { + testForRuntime(parameters) .addProgramClasses(Main.class, A.class) .addProgramClassFileData(generateTestClass()) - .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), Main.class) - .writeProcessResult(System.out) .assertSuccessWithOutput(expectedOutput); } @@ -129,7 +124,7 @@ MethodVisitor mv; classWriter.visit( - Opcodes.V1_8, + Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER | Opcodes.ACC_ENUM, DescriptorUtils.getBinaryNameFromJavaType(generatedTestClassName), null, @@ -165,15 +160,19 @@ mv.visitVarInsn(Opcodes.ALOAD, 2); }); - printCompareIntergers("Hashcode: ", mv, (mvCopy) -> { - assert mv == mvCopy; - // Invoke hashCode using both java.lang.Object and array type an holder. - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false); + printCompareIntegers( + "Hashcode: ", + mv, + (mvCopy) -> { + assert mv == mvCopy; + // Invoke hashCode using both java.lang.Object and array type an holder. + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false); - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, arrayTypeDescriptor, "hashCode", "()I", false); - }); + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn( + Opcodes.INVOKEVIRTUAL, arrayTypeDescriptor, "hashCode", "()I", false); + }); printBoolean("Compare with Object: ", mv, (mvCopy) -> { assert mv == mvCopy; @@ -213,7 +212,7 @@ Opcodes.INVOKEVIRTUAL, arrayTypeDescriptor, "notPresent", "()Ljava/lang/String;", false); mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(-1, -1); + mv.visitMaxs(10, 10); mv.visitEnd(); } @@ -221,7 +220,8 @@ return classWriter.toByteArray(); } - public static void printCompareIntergers( + + public static void printCompareIntegers( String header, MethodVisitor mv, Consumer<MethodVisitor> consumer) { mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn(header);
diff --git a/src/test/java/com/android/tools/r8/regress/b152973695/CompileToInvalidFileTest.java b/src/test/java/com/android/tools/r8/regress/b152973695/CompileToInvalidFileTest.java index c96cbda..745d166 100644 --- a/src/test/java/com/android/tools/r8/regress/b152973695/CompileToInvalidFileTest.java +++ b/src/test/java/com/android/tools/r8/regress/b152973695/CompileToInvalidFileTest.java
@@ -51,7 +51,7 @@ ? new ClassFileConsumer.ArchiveConsumer(INVALID_FILE) : new ArchiveConsumer(INVALID_FILE); try { - testForD8() + testForD8(Backend.fromConsumer(programConsumer)) .addProgramClasses(Main.class) .setProgramConsumer(programConsumer) .compileWithExpectedDiagnostics(diagnostics -> checkDiagnostics(diagnostics, true)); @@ -69,7 +69,7 @@ ? new ClassFileConsumer.ArchiveConsumer(INVALID_FILE) : new ArchiveConsumer(INVALID_FILE); try { - testForR8(classFileConsumer ? Backend.CF : Backend.DEX) + testForR8(Backend.fromConsumer(programConsumer)) .addProgramClasses(Main.class) .addKeepMainRule(Main.class) .setProgramConsumer(programConsumer)
diff --git a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java index 8f3eea0..0afec27 100644 --- a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java +++ b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
@@ -3,73 +3,106 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.regress.b78493232; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.Assume.assumeTrue; import com.android.tools.r8.AsmTestBase; -import com.android.tools.r8.ToolHelper; -import com.android.tools.r8.ToolHelper.ProcessResult; -import com.android.tools.r8.utils.AndroidApp; +import com.android.tools.r8.D8TestRunResult; +import com.android.tools.r8.R8TestRunResult; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRunResult; import com.android.tools.r8.utils.StringUtils; +import com.google.common.collect.ImmutableList; +import java.util.List; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; // Variant of Regress78493232, but where the new-instance is forced to flow to a non-trivial phi // function prior to the call to <init>. Due to the non-trivial phi this JVM code will not pass // the verifier. This test is kept to allow inspection of the code path hit in D8/R8 for such // inputs, but besides that just documents the behaviour on the various VMs. +@RunWith(Parameterized.class) public class Regress78493232_WithPhi extends AsmTestBase { - static final String expected = + private static final String EXPECTED = StringUtils.lines( "After 0 iterations, expected \"java.security.SecureRandom\", but got \"null\""); + private static final String MAIN = Regress78493232Dump_WithPhi.CLASS_NAME; + private static final List<Class<?>> CLASSES = ImmutableList.of(Regress78493232Utils.class); + private static final List<byte[]> CLASS_BYTES = + ImmutableList.of(Regress78493232Dump_WithPhi.dump()); + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public Regress78493232_WithPhi(TestParameters parameters) { + this.parameters = parameters; + } + @Test - public void test() throws Exception { - AndroidApp app = - buildAndroidApp( - Regress78493232Dump_WithPhi.dump(), - ToolHelper.getClassAsBytes(Regress78493232Utils.class)); - ProcessResult javaResult = - runOnJavaRawNoVerify( - Regress78493232Dump_WithPhi.CLASS_NAME, - Regress78493232Dump_WithPhi.dump(), - ToolHelper.getClassAsBytes(Regress78493232Utils.class)); - ProcessResult d8Result = - runOnArtRaw(compileWithD8(app), Regress78493232Dump_WithPhi.CLASS_NAME); - ProcessResult r8Result = - runOnArtRaw( - compileWithR8(app, "-dontshrink\n-dontobfuscate\n"), - Regress78493232Dump_WithPhi.CLASS_NAME); - String proguardConfig = - keepMainProguardConfiguration(Regress78493232Dump_WithPhi.CLASS_NAME) + "-dontobfuscate\n"; - ProcessResult r8ShakenResult = - runOnArtRaw(compileWithR8(app, proguardConfig), Regress78493232Dump_WithPhi.CLASS_NAME); - assertEquals(expected, javaResult.stdout); - assertEquals(0, javaResult.exitCode); - switch (ToolHelper.getDexVm().getVersion()) { + public void testReference() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .noVerify() + .addProgramClassFileData(CLASS_BYTES) + .addProgramClasses(CLASSES) + .run(parameters.getRuntime(), MAIN) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testD8() throws Exception { + assumeTrue(parameters.isDexRuntime()); + D8TestRunResult result = + testForD8() + .addProgramClasses(CLASSES) + .addProgramClassFileData(CLASS_BYTES) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), MAIN); + checkResult(result); + } + + @Test + public void testR8() throws Exception { + testR8(true); + } + + @Test + public void testNoTreeShakingR8() throws Exception { + testR8(false); + } + + private void testR8(boolean treeShake) throws Exception { + assumeTrue(parameters.isDexRuntime()); + R8TestRunResult result = + testForR8(parameters.getBackend()) + .addProgramClasses(CLASSES) + .addProgramClassFileData(CLASS_BYTES) + .treeShaking(treeShake) + .noMinification() + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(MAIN) + .run(parameters.getRuntime(), MAIN); + checkResult(result); + } + + private void checkResult(TestRunResult<?> result) { + switch (parameters.getDexRuntimeVersion()) { case V6_0_1: - assertEquals("Completed successfully after 1000 iterations\n", d8Result.stdout); - assertEquals("Completed successfully after 1000 iterations\n", r8Result.stdout); - assertEquals("Completed successfully after 1000 iterations\n", r8ShakenResult.stdout); - assertEquals(0, d8Result.exitCode); - assertEquals(0, r8Result.exitCode); - assertEquals(0, r8ShakenResult.exitCode); + result.assertSuccessWithOutput("Completed successfully after 1000 iterations\n"); break; case V5_1_1: - assertEquals(expected, d8Result.stdout); - assertEquals(expected, r8Result.stdout); - assertEquals(expected, r8ShakenResult.stdout); - assertEquals(0, d8Result.exitCode); - assertEquals(0, r8Result.exitCode); - assertEquals(0, r8ShakenResult.exitCode); + result.assertSuccessWithOutput(EXPECTED); break; default: - assertNotEquals(-1, d8Result.stderr.indexOf("java.lang.VerifyError")); - assertNotEquals(-1, r8Result.stderr.indexOf("java.lang.VerifyError")); - assertNotEquals(-1, r8ShakenResult.stderr.indexOf("java.lang.VerifyError")); - assertEquals(1, d8Result.exitCode); - assertEquals(1, r8Result.exitCode); - assertEquals(1, r8ShakenResult.exitCode); + result.assertFailureWithErrorThatThrows(VerifyError.class); break; } }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java new file mode 100644 index 0000000..47157aa --- /dev/null +++ b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
@@ -0,0 +1,101 @@ +// 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.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.repackage.testclasses.repackagetest.TestClass; +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; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class RepackageAfterCollisionWithPackagePrivateSignatureTest extends TestBase { + + private static final String FLATTEN_PACKAGE_HIERARCHY = "flattenpackagehierarchy"; + private static final String REPACKAGE_CLASSES = "repackageclasses"; + 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().withAllRuntimesAndApiLevels().build()); + } + + public RepackageAfterCollisionWithPackagePrivateSignatureTest( + String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) { + this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses; + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForR8(parameters.getBackend()) + .addInnerClasses(RepackageAfterCollisionWithPackagePrivateSignatureTest.class) + .addKeepClassAndMembersRules(TestClass.class) + .addKeepRules( + "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_DIR + "\"") + .addClassObfuscationDictionary("a") + .addOptionsModification(options -> options.testing.enableExperimentalRepackaging = true) + .enableInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect(this::inspect) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("Hello world!"); + } + + private void inspect(CodeInspector inspector) { + ClassSubject repackageClassSubject = inspector.clazz(RepackageCandidate.class); + assertThat(repackageClassSubject, isPresent()); + assertEquals( + flattenPackageHierarchyOrRepackageClasses.equals(FLATTEN_PACKAGE_HIERARCHY) + ? REPACKAGE_DIR + ".a" + : REPACKAGE_DIR, + repackageClassSubject.getDexProgramClass().getType().getPackageName()); + } + + public static class TestClass { + + public static void main(String[] args) { + RepackageCandidate.foo(0); + RepackageCandidate.foo((int) System.currentTimeMillis(), 0); + } + + static void restrictToCurrentPackage() { + System.out.print("Hello"); + } + } + + public static class RepackageCandidate { + + public static void foo(int unused) { + TestClass.restrictToCurrentPackage(); + } + + @NeverInline + public static void foo(int used, int unused) { + if (used >= 0) { + System.out.println(" world!"); + } + } + } +}
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 6d468f4..69a88d0 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -7,6 +7,7 @@ import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import com.android.tools.r8.TestBase; @@ -47,6 +48,8 @@ @RunWith(Parameterized.class) public class RepackageTest extends TestBase { + private static final String FLATTEN_PACKAGE_HIERARCHY = "flattenpackagehierarchy"; + private static final String REPACKAGE_CLASSES = "repackageclasses"; private static final String REPACKAGE_DIR = "foo"; private static final List<String> EXPECTED = @@ -68,28 +71,35 @@ "ReachableClass.packagePrivateMethod()"); private final boolean allowAccessModification; + private final boolean enableExperimentalRepackaging; private final String flattenPackageHierarchyOrRepackageClasses; private final TestParameters parameters; - @Parameters(name = "{1}, allow access modification: {0}") + @Parameters(name = "{3}, allow access modification: {0}, experimental: {1}, kind: {2}") public static List<Object[]> data() { return buildParameters( BooleanUtils.values(), - ImmutableList.of("flattenpackagehierarchy", "repackageclasses"), + BooleanUtils.values(), + ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES), getTestParameters().withAllRuntimesAndApiLevels().build()); } public RepackageTest( boolean allowAccessModification, + boolean enableExperimentalRepackaging, String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) { this.allowAccessModification = allowAccessModification; + this.enableExperimentalRepackaging = enableExperimentalRepackaging; this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses; this.parameters = parameters; } @Test public void testJvm() throws Exception { + assumeFalse(allowAccessModification); + assumeFalse(enableExperimentalRepackaging); + assumeTrue(flattenPackageHierarchyOrRepackageClasses.equals(FLATTEN_PACKAGE_HIERARCHY)); assumeTrue(parameters.isCfRuntime()); testForJvm() .addTestClasspath() @@ -99,6 +109,7 @@ @Test public void testR8() throws Exception { + assumeTrue(!enableExperimentalRepackaging || parameters.isCfRuntime()); testForR8(parameters.getBackend()) .addProgramFiles(ToolHelper.getClassFilesForTestPackage(TestClass.class.getPackage())) .addKeepMainRule(TestClass.class) @@ -115,6 +126,9 @@ " <methods>;", "}") .allowAccessModification(allowAccessModification) + .addOptionsModification( + options -> + options.testing.enableExperimentalRepackaging = enableExperimentalRepackaging) .enableInliningAnnotations() .enableMergeAnnotations() .setMinApi(parameters.getApiLevel()) @@ -132,9 +146,9 @@ if (eligibleForRepackaging) { assertEquals( clazz.getTypeName(), - flattenPackageHierarchyOrRepackageClasses.equals("flattenpackagehierarchy") + flattenPackageHierarchyOrRepackageClasses.equals(FLATTEN_PACKAGE_HIERARCHY) ? REPACKAGE_DIR + ".a" - : REPACKAGE_DIR + "", + : REPACKAGE_DIR, subject.getDexProgramClass().getType().getPackageName()); } else { assertEquals( @@ -154,7 +168,7 @@ // the consumer, since these classes should be repackaged independent of // -allowaccessmodification. Consumer<Class<?>> markShouldAlwaysBeEligible = - clazz -> consumer.accept(clazz, allowAccessModification); + clazz -> consumer.accept(clazz, allowAccessModification || enableExperimentalRepackaging); Consumer<Class<?>> markEligibleWithAllowAccessModification = clazz -> consumer.accept(clazz, allowAccessModification);
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java index a7af296..8089eb2 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java
@@ -11,7 +11,7 @@ public class AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect { @NeverInline - static void test() { + public static void test() { ReachableClassWithKeptMethodAllowRenaming.packagePrivateMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java index 9310128..c7c3695 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java
@@ -11,7 +11,16 @@ public class AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect { @NeverInline - static void test() { - AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.test(); + public static void test() { + Helper.test(); + } + + @NeverMerge + public static class Helper { + + @NeverInline + static void test() { + ReachableClassWithKeptMethodAllowRenaming.packagePrivateMethod(); + } } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java index 1c159f0..6948b55 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java
@@ -11,7 +11,7 @@ public class AccessPackagePrivateKeptMethodOnReachableClassDirect { @NeverInline - static void test() { + public static void test() { ReachableClassWithKeptMethod.packagePrivateMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java index 043c43a..7d5baae 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java
@@ -11,7 +11,16 @@ public class AccessPackagePrivateKeptMethodOnReachableClassIndirect { @NeverInline - static void test() { - AccessPackagePrivateKeptMethodOnReachableClassDirect.test(); + public static void test() { + Helper.test(); + } + + @NeverMerge + public static class Helper { + + @NeverInline + static void test() { + ReachableClassWithKeptMethod.packagePrivateMethod(); + } } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java index 45049a6..f3a90e6 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java
@@ -11,7 +11,7 @@ public class AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect { @NeverInline - static void test() { + public static void test() { KeptClassAllowRenaming.packagePrivateMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java index 8ff327f..ddfd95b 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java
@@ -11,7 +11,16 @@ public class AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect { @NeverInline - static void test() { - AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.test(); + public static void test() { + Helper.test(); + } + + @NeverMerge + public static class Helper { + + @NeverInline + static void test() { + KeptClassAllowRenaming.packagePrivateMethod(); + } } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java index 8ae7f71..11110bd 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java
@@ -11,7 +11,7 @@ public class AccessPackagePrivateMethodOnKeptClassDirect { @NeverInline - static void test() { + public static void test() { KeptClass.packagePrivateMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java index 6e769dd..0b737ff 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java
@@ -11,7 +11,16 @@ public class AccessPackagePrivateMethodOnKeptClassIndirect { @NeverInline - static void test() { - AccessPackagePrivateMethodOnKeptClassDirect.test(); + public static void test() { + Helper.test(); + } + + @NeverMerge + public static class Helper { + + @NeverInline + static void test() { + KeptClass.packagePrivateMethod(); + } } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java index 8ef5364..f9a5b76 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java
@@ -11,7 +11,7 @@ public class AccessPackagePrivateMethodOnReachableClassDirect { @NeverInline - static void test() { + public static void test() { ReachableClass.packagePrivateMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java index 63d0072..2c0a1b2 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java
@@ -11,7 +11,16 @@ public class AccessPackagePrivateMethodOnReachableClassIndirect { @NeverInline - static void test() { - AccessPackagePrivateMethodOnReachableClassDirect.test(); + public static void test() { + Helper.test(); + } + + @NeverMerge + public static class Helper { + + @NeverInline + static void test() { + ReachableClass.packagePrivateMethod(); + } } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java index 460e3e1..0f54397 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java
@@ -11,7 +11,7 @@ public class AccessPublicKeptMethodAllowRenamingOnReachableClass { @NeverInline - static void test() { + public static void test() { ReachableClassWithKeptMethodAllowRenaming.publicMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java index be42852..dcd6aa4 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java
@@ -11,7 +11,7 @@ public class AccessPublicKeptMethodOnReachableClass { @NeverInline - static void test() { + public static void test() { ReachableClassWithKeptMethod.publicMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java index 54f999d..f6cf98a 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java
@@ -11,7 +11,7 @@ public class AccessPublicMethodOnKeptClass { @NeverInline - static void test() { + public static void test() { KeptClass.publicMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java index 16acfb5..05f943c 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java
@@ -11,7 +11,7 @@ public class AccessPublicMethodOnKeptClassAllowRenaming { @NeverInline - static void test() { + public static void test() { KeptClassAllowRenaming.publicMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java index 4414fd6..0c21cef 100644 --- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java +++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java
@@ -11,7 +11,7 @@ public class AccessPublicMethodOnReachableClass { @NeverInline - static void test() { + public static void test() { ReachableClass.publicMethod(); } }
diff --git a/src/test/java/com/android/tools/r8/resolution/AsmBasedTests.java b/src/test/java/com/android/tools/r8/resolution/AsmBasedTests.java deleted file mode 100644 index 7264dd7..0000000 --- a/src/test/java/com/android/tools/r8/resolution/AsmBasedTests.java +++ /dev/null
@@ -1,34 +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.resolution; - -import com.android.tools.r8.AsmTestBase; -import com.android.tools.r8.resolution.shadowing1.AClassDump; -import com.android.tools.r8.resolution.shadowing1.InterfaceDump; -import com.android.tools.r8.resolution.shadowing1.MainDump; -import com.android.tools.r8.resolution.shadowing1.SubInterfaceDump; -import org.junit.Ignore; -import org.junit.Test; - -public class AsmBasedTests extends AsmTestBase { - - @Test - @Ignore("b/69356146") - public void defaultMethodShadowedByStatic() throws Exception { - ensureException("Main", IncompatibleClassChangeError.class, - InterfaceDump.dump(), - SubInterfaceDump.dump(), - AClassDump.dump(), - MainDump.dump()); - } - - @Test - @Ignore("b/69356146") - public void invokeDefaultMethodViaStatic() throws Exception { - ensureException("Main", IncompatibleClassChangeError.class, - com.android.tools.r8.resolution.invokestaticinterfacedefault.InterfaceDump.dump(), - com.android.tools.r8.resolution.invokestaticinterfacedefault.MainDump.dump()); - - } -}
diff --git a/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java b/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java new file mode 100644 index 0000000..19424d8 --- /dev/null +++ b/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java
@@ -0,0 +1,69 @@ +// 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.resolution; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRunResult; +import com.android.tools.r8.ToolHelper.DexVm.Version; +import com.android.tools.r8.resolution.shadowing1.AClassDump; +import com.android.tools.r8.resolution.shadowing1.InterfaceDump; +import com.android.tools.r8.resolution.shadowing1.MainDump; +import com.android.tools.r8.resolution.shadowing1.SubInterfaceDump; +import com.google.common.collect.ImmutableList; +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 DefaultMethodShadowedByStaticTest extends TestBase { + + private final List<byte[]> CLASSES = + ImmutableList.of( + InterfaceDump.dump(), SubInterfaceDump.dump(), AClassDump.dump(), MainDump.dump()); + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + private final TestParameters parameters; + + public DefaultMethodShadowedByStaticTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testReference() throws Exception { + TestRunResult<?> result = + testForRuntime(parameters) + .addProgramClassFileData(CLASSES) + .run(parameters.getRuntime(), "Main"); + if (parameters.isDexRuntime() + && (parameters.getApiLevel().isLessThan(apiLevelWithStaticInterfaceMethodsSupport()) + || parameters.getDexRuntimeVersion().equals(Version.V7_0_0))) { + // TODO(b/167535447): Desugaring should preserve the error. + result.assertSuccessWithOutputLines("42"); + } else if (parameters.isDexRuntime() + && parameters.getDexRuntimeVersion().equals(Version.V7_0_0)) { + // Note: VM 7.0.0 without desugaring of defaults will incorrectly allow the virtual dispatch. + result.assertSuccessWithOutputLines("42"); + } else { + result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); + } + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClassFileData(CLASSES) + .addKeepMainRule("Main") + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), "Main") + .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); + } +}
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokeDefaultMethodViaStaticTest.java b/src/test/java/com/android/tools/r8/resolution/InvokeDefaultMethodViaStaticTest.java new file mode 100644 index 0000000..2080b42 --- /dev/null +++ b/src/test/java/com/android/tools/r8/resolution/InvokeDefaultMethodViaStaticTest.java
@@ -0,0 +1,68 @@ +// 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.resolution; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRunResult; +import com.android.tools.r8.resolution.invokestaticinterfacedefault.InterfaceDump; +import com.android.tools.r8.resolution.invokestaticinterfacedefault.MainDump; +import com.google.common.collect.ImmutableList; +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 InvokeDefaultMethodViaStaticTest extends TestBase { + + private static final List<byte[]> CLASSES = + ImmutableList.of(InterfaceDump.dump(), MainDump.dump()); + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + private final TestParameters parameters; + + public InvokeDefaultMethodViaStaticTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testReference() throws Exception { + TestRunResult<?> result = + testForRuntime(parameters) + .addProgramClassFileData(CLASSES) + .run(parameters.getRuntime(), "Main"); + if (parameters.isDexRuntime() + && parameters.getApiLevel().isLessThan(apiLevelWithDefaultInterfaceMethodsSupport())) { + // TODO(b/167535447): Desugaring should preserve the error. + result.assertFailureWithErrorThatThrows(NoSuchMethodError.class); + } else { + result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); + } + } + + @Test + public void testR8() throws Exception { + TestRunResult<?> result = + testForR8(parameters.getBackend()) + .addProgramClassFileData(CLASSES) + .addKeepMainRule("Main") + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(o -> o.testing.allowInvokeErrors = true) + .run(parameters.getRuntime(), "Main"); + if (parameters.isDexRuntime() + && parameters.getApiLevel().isLessThan(apiLevelWithDefaultInterfaceMethodsSupport())) { + // TODO(b/167535447): Desugaring should preserve the error. + result.assertFailureWithErrorThatThrows(NoClassDefFoundError.class); + } else { + result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/InterfaceDump.java b/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/InterfaceDump.java index 56d67aa..37a6f2b 100644 --- a/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/InterfaceDump.java +++ b/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/InterfaceDump.java
@@ -22,7 +22,7 @@ */ public class InterfaceDump implements Opcodes { - public static byte[] dump() throws Exception { + public static byte[] dump() { ClassWriter cw = new ClassWriter(0); FieldVisitor fv;
diff --git a/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/MainDump.java b/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/MainDump.java index 15f12b9..0de68a4 100644 --- a/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/MainDump.java +++ b/src/test/java/com/android/tools/r8/resolution/invokestaticinterfacedefault/MainDump.java
@@ -14,7 +14,7 @@ */ public class MainDump implements Opcodes { - public static byte[] dump() throws Exception { + public static byte[] dump() { ClassWriter cw = new ClassWriter(0); FieldVisitor fv;
diff --git a/src/test/java/com/android/tools/r8/resolution/shadowing1/AClassDump.java b/src/test/java/com/android/tools/r8/resolution/shadowing1/AClassDump.java index 9701db0..7f1be60 100644 --- a/src/test/java/com/android/tools/r8/resolution/shadowing1/AClassDump.java +++ b/src/test/java/com/android/tools/r8/resolution/shadowing1/AClassDump.java
@@ -19,7 +19,7 @@ */ public class AClassDump implements Opcodes { - public static byte[] dump() throws Exception { + public static byte[] dump() { ClassWriter cw = new ClassWriter(0); FieldVisitor fv;
diff --git a/src/test/java/com/android/tools/r8/resolution/shadowing1/InterfaceDump.java b/src/test/java/com/android/tools/r8/resolution/shadowing1/InterfaceDump.java index 603071a..cc8b019 100644 --- a/src/test/java/com/android/tools/r8/resolution/shadowing1/InterfaceDump.java +++ b/src/test/java/com/android/tools/r8/resolution/shadowing1/InterfaceDump.java
@@ -11,7 +11,7 @@ public class InterfaceDump implements Opcodes { - public static byte[] dump() throws Exception { + public static byte[] dump() { ClassWriter cw = new ClassWriter(0); FieldVisitor fv;
diff --git a/src/test/java/com/android/tools/r8/resolution/shadowing1/MainDump.java b/src/test/java/com/android/tools/r8/resolution/shadowing1/MainDump.java index 09bd3b2..b21c15f 100644 --- a/src/test/java/com/android/tools/r8/resolution/shadowing1/MainDump.java +++ b/src/test/java/com/android/tools/r8/resolution/shadowing1/MainDump.java
@@ -23,7 +23,7 @@ */ public class MainDump implements Opcodes { - public static byte[] dump() throws Exception { + public static byte[] dump() { ClassWriter cw = new ClassWriter(0); FieldVisitor fv;
diff --git a/src/test/java/com/android/tools/r8/resolution/shadowing1/SubInterfaceDump.java b/src/test/java/com/android/tools/r8/resolution/shadowing1/SubInterfaceDump.java index f70cf4f..7e51c28 100644 --- a/src/test/java/com/android/tools/r8/resolution/shadowing1/SubInterfaceDump.java +++ b/src/test/java/com/android/tools/r8/resolution/shadowing1/SubInterfaceDump.java
@@ -11,7 +11,7 @@ public class SubInterfaceDump implements Opcodes { - public static byte[] dump() throws Exception { + public static byte[] dump() { ClassWriter cw = new ClassWriter(0); FieldVisitor fv;
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 2bb72cd..ac64695 100644 --- a/src/test/java/com/android/tools/r8/utils/Smali.java +++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -8,6 +8,8 @@ import com.android.tools.r8.DiagnosticsHandler; import com.android.tools.r8.dex.ApplicationReader; import com.android.tools.r8.dex.ApplicationWriter; +import com.android.tools.r8.graph.AppInfo; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InitClassLens; @@ -114,7 +116,7 @@ ApplicationWriter writer = new ApplicationWriter( dexApp, - null, + AppView.createForD8(AppInfo.createInitialAppInfo(dexApp)), options, null, GraphLens.getIdentityLens(),
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 59c8760..3125afe 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
@@ -183,4 +183,9 @@ public ClassNamingForNameMapper getNaming() { return null; } + + @Override + public void disassembleUsingJavap(boolean verbose) throws Exception { + throw new Unreachable("Cannot disassembly an absent class"); + } }
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 b2266ce..28fd839 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
@@ -214,4 +214,6 @@ } public abstract ClassNamingForNameMapper getNaming(); + + public abstract void disassembleUsingJavap(boolean verbose) throws Exception; }
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 0b1d950..f12840f 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
@@ -7,6 +7,9 @@ import static com.android.tools.r8.KotlinTestBase.METADATA_TYPE; import static org.junit.Assert.assertTrue; +import com.android.tools.r8.TestRuntime.CfRuntime; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.ToolHelper.ProcessResult; import com.android.tools.r8.graph.DexAnnotation; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; @@ -27,6 +30,7 @@ import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.StringUtils; +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import kotlinx.metadata.jvm.KotlinClassMetadata; @@ -408,4 +412,25 @@ public ClassNamingForNameMapper getNaming() { return naming; } + + @Override + public void disassembleUsingJavap(boolean verbose) throws Exception { + assert dexClass.origin != null; + List<String> command = new ArrayList<>(); + command.add( + CfRuntime.getCheckedInJdk9().getJavaHome().resolve("bin").resolve("javap").toString()); + if (verbose) { + command.add("-v"); + command.add("-c"); + command.add("-p"); + } + command.add("-cp"); + List<String> parts = dexClass.origin.parts(); + assert parts.size() == 2; + command.add(parts.get(0)); + command.add(parts.get(1).replace(".class", "")); + ProcessResult processResult = ToolHelper.runProcess(new ProcessBuilder(command)); + assert processResult.exitCode == 0; + System.out.println(processResult.stdout); + } }