Merge commit '51b015b7c4d252305d76a5c8beddf9e57bc02ef9' into dev-release Change-Id: Ia1164268c10ecdb2c5f5d26ac86130497dda48d1
diff --git a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java index d3ee009..392a4bb 100644 --- a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java +++ b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
@@ -19,6 +19,7 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.NoSuchFileException; @@ -116,7 +117,7 @@ if (!Files.exists(archive)) { throw new NoSuchFileException(archive.toString()); } else { - throw e; + throw new UncheckedIOException(archive.toString(), e); } } lazyDescriptors = new HashSet<>();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java index 131ec35..178aa89 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -1804,41 +1804,41 @@ // android.os.Build$VERSION_CODES_FULL Object[][] versionCodesFull = { - {"BASE", 10_000}, - {"BASE_1_1", 20_000}, - {"CUPCAKE", 30_000}, - {"DONUT", 40_000}, - {"ECLAIR", 50_000}, - {"ECLAIR_0_1", 60_000}, - {"ECLAIR_MR1", 70_000}, - {"FROYO", 80_000}, - {"GINGERBREAD", 90_000}, - {"GINGERBREAD_MR1", 100_000}, - {"HONEYCOMB", 110_000}, - {"HONEYCOMB_MR1", 120_000}, - {"HONEYCOMB_MR2", 130_000}, - {"ICE_CREAM_SANDWICH", 140_000}, - {"ICE_CREAM_SANDWICH_MR1", 150_000}, - {"JELLY_BEAN", 160_000}, - {"JELLY_BEAN_MR1", 170_000}, - {"JELLY_BEAN_MR2", 180_000}, - {"KITKAT", 190_000}, - {"KITKAT_WATCH", 200_000}, - {"LOLLIPOP", 210_000}, - {"LOLLIPOP_MR1", 220_000}, - {"M", 230_000}, - {"N", 240_000}, - {"N_MR1", 250_000}, - {"O", 260_000}, - {"O_MR1", 270_000}, - {"P", 280_000}, - {"Q", 290_000}, - {"R", 300_000}, - {"S", 310_000}, - {"S_V2", 320_000}, - {"TIRAMISU", 330_000}, - {"UPSIDE_DOWN_CAKE", 340_000}, - {"VANILLA_ICE_CREAM", 350_000}, + {"BASE", 100_000}, + {"BASE_1_1", 200_000}, + {"CUPCAKE", 300_000}, + {"DONUT", 400_000}, + {"ECLAIR", 500_000}, + {"ECLAIR_0_1", 600_000}, + {"ECLAIR_MR1", 700_000}, + {"FROYO", 800_000}, + {"GINGERBREAD", 900_000}, + {"GINGERBREAD_MR1", 1000_000}, + {"HONEYCOMB", 1100_000}, + {"HONEYCOMB_MR1", 1200_000}, + {"HONEYCOMB_MR2", 1300_000}, + {"ICE_CREAM_SANDWICH", 1400_000}, + {"ICE_CREAM_SANDWICH_MR1", 1500_000}, + {"JELLY_BEAN", 1600_000}, + {"JELLY_BEAN_MR1", 1700_000}, + {"JELLY_BEAN_MR2", 1800_000}, + {"KITKAT", 1900_000}, + {"KITKAT_WATCH", 2000_000}, + {"LOLLIPOP", 2100_000}, + {"LOLLIPOP_MR1", 2200_000}, + {"M", 2300_000}, + {"N", 2400_000}, + {"N_MR1", 2500_000}, + {"O", 2600_000}, + {"O_MR1", 2700_000}, + {"P", 2800_000}, + {"Q", 2900_000}, + {"R", 3000_000}, + {"S", 3100_000}, + {"S_V2", 3200_000}, + {"TIRAMISU", 3300_000}, + {"UPSIDE_DOWN_CAKE", 3400_000}, + {"VANILLA_ICE_CREAM", 3500_000}, }; type = factory.createType("Landroid/os/Build$VERSION_CODES_FULL;"); for (Object[] versionCodeFull : versionCodesFull) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java index 932bf0e..b562fbb 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.optimize; +import static com.android.tools.r8.ir.regalloc.LiveIntervals.NO_REGISTER; + import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DebugLocalInfo; import com.android.tools.r8.ir.code.BasicBlock; @@ -231,13 +233,45 @@ public static void shareIdenticalBlockSuffix( IRCode code, RegisterAllocator allocator, int overhead) { Collection<BasicBlock> blocks = code.blocks; - BasicBlock normalExit = null; List<BasicBlock> normalExits = code.computeNormalExitBlocks(); + Set<BasicBlock> syntheticNormalExits = Sets.newIdentityHashSet(); if (normalExits.size() > 1) { - normalExit = new BasicBlock(code.metadata()); - normalExit.getMutablePredecessors().addAll(normalExits); - blocks = new ArrayList<>(code.blocks); - blocks.add(normalExit); + if (code.context().getReturnType().isVoidType() + || code.getConversionOptions().isGeneratingClassFiles()) { + BasicBlock syntheticNormalExit = new BasicBlock(code.metadata()); + syntheticNormalExit.getMutablePredecessors().addAll(normalExits); + syntheticNormalExits.add(syntheticNormalExit); + } else { + Int2ReferenceMap<List<BasicBlock>> normalExitPartitioning = + new Int2ReferenceOpenHashMap<>(); + for (BasicBlock block : normalExits) { + int returnRegister = + block + .exit() + .asReturn() + .returnValue() + .getLiveIntervals() + .getSplitCovering(block.exit().getNumber()) + .getRegister(); + assert returnRegister != NO_REGISTER; + List<BasicBlock> blocksWithReturnRegister; + if (normalExitPartitioning.containsKey(returnRegister)) { + blocksWithReturnRegister = normalExitPartitioning.get(returnRegister); + } else { + blocksWithReturnRegister = new ArrayList<>(); + normalExitPartitioning.put(returnRegister, blocksWithReturnRegister); + } + blocksWithReturnRegister.add(block); + } + for (List<BasicBlock> blocksWithSameReturnRegister : normalExitPartitioning.values()) { + BasicBlock syntheticNormalExit = new BasicBlock(code.metadata()); + syntheticNormalExit.getMutablePredecessors().addAll(blocksWithSameReturnRegister); + syntheticNormalExits.add(syntheticNormalExit); + } + } + blocks = new ArrayList<>(code.getBlocks().size() + syntheticNormalExits.size()); + blocks.addAll(code.getBlocks()); + blocks.addAll(syntheticNormalExits); } do { Map<BasicBlock, BasicBlock> newBlocks = new IdentityHashMap<>(); @@ -295,7 +329,7 @@ code, commonSuffixSize, predsWithSameLastInstruction, - block == normalExit ? null : block, + syntheticNormalExits.contains(block) ? null : block, allocator); newBlocks.put(predsWithSameLastInstruction.get(0), newBlock); }
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java index bc8b11b..ac612a7 100644 --- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java +++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -367,6 +367,7 @@ constrainArgumentIntervals(); insertRangeInvokeMoves(); ImmutableList<BasicBlock> blocks = computeLivenessInformation(); + dedupCatchHandlerBlocks(); timing.end(); timing.begin("Allocate"); performAllocation(); @@ -3428,6 +3429,77 @@ code.blocks.forEach(BasicBlock::clearUserInfo); } + private void dedupCatchHandlerBlocks() { + List<BasicBlock> candidateBlocks = new ArrayList<>(); + for (BasicBlock block : code.getBlocks()) { + if (block.hasUniquePredecessor() + && block.getUniquePredecessor().hasCatchSuccessor(block) + && liveAtEntrySets.get(block).isEmpty() + && block.size() <= 2) { + candidateBlocks.add(block); + } + } + if (candidateBlocks.isEmpty()) { + return; + } + Set<BasicBlock> removedBlocks = Sets.newIdentityHashSet(); + for (BasicBlock candidateBlock : candidateBlocks) { + assert !removedBlocks.contains(candidateBlock); + BasicBlock equivalentBlock = null; + for (BasicBlock block : candidateBlocks) { + if (block == candidateBlock || removedBlocks.contains(block)) { + continue; + } + if (isEquivalentCatchHandlers(candidateBlock, block)) { + equivalentBlock = block; + break; + } + } + if (equivalentBlock == null) { + continue; + } + assert !candidateBlock.hasCatchHandlers(); + removedBlocks.add(candidateBlock); + for (BasicBlock tryBlock : candidateBlock.getPredecessors()) { + tryBlock.replaceSuccessor(candidateBlock, equivalentBlock); + if (!equivalentBlock.getPredecessors().contains(tryBlock)) { + equivalentBlock.getMutablePredecessors().add(tryBlock); + } + } + for (BasicBlock successor : candidateBlock.getSuccessors()) { + int index = successor.getPredecessors().indexOf(candidateBlock); + successor.getMutablePredecessors().remove(index); + for (Phi phi : successor.getPhis()) { + phi.removeOperand(index); + } + } + } + code.removeBlocks(removedBlocks); + } + + // TODO(b/153139043): Generalize this. Maybe use BasicBlock subsumption. + private boolean isEquivalentCatchHandlers(BasicBlock block, BasicBlock other) { + assert liveAtEntrySets.get(block).isEmpty(); + assert liveAtEntrySets.get(other).isEmpty(); + if (block.size() != other.size() || block.size() > 2) { + return false; + } + if (block.size() == 2) { + if (!block.entry().isMoveException() || !other.entry().isMoveException()) { + return false; + } + } + if (block.exit().isGoto() + && other.exit().isGoto() + && block.getUniqueNormalSuccessor() == other.getUniqueNormalSuccessor()) { + return true; + } + if (block.exit().isReturn() && other.exit().isReturn()) { + return true; + } + return false; + } + // Rewrites casts on the form "lhs = (T) rhs" into "(T) rhs" and replaces the uses of lhs by rhs. // This transformation helps to ensure that we do not insert unnecessary moves in bridge methods // with an invoke-range instruction, since all the arguments to the invoke-range instruction will
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java index 165e520..945616f 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -43,7 +43,6 @@ private boolean printMapping; private Path printMappingFile; private Path applyMappingFile; - private boolean verbose; private String renameSourceFileAttribute; private final List<String> keepAttributePatterns = new ArrayList<>(); private final ProguardClassFilter.Builder keepPackageNamesPatterns = @@ -183,10 +182,6 @@ return applyMappingFile != null; } - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - public void setRenameSourceFileAttribute(String renameSourceFileAttribute) { this.renameSourceFileAttribute = renameSourceFileAttribute; } @@ -335,7 +330,6 @@ printMapping, printMappingFile, applyMappingFile, - verbose, renameSourceFileAttribute, ProguardKeepAttributes.fromPatterns(keepAttributePatterns), keepPackageNamesPatterns.build(), @@ -394,7 +388,6 @@ private final boolean printMapping; private final Path printMappingFile; private final Path applyMappingFile; - private final boolean verbose; private final String renameSourceFileAttribute; private final ProguardKeepAttributes keepAttributes; private final ProguardClassFilter keepPackageNamesPatterns; @@ -435,7 +428,6 @@ boolean printMapping, Path printMappingFile, Path applyMappingFile, - boolean verbose, String renameSourceFileAttribute, ProguardKeepAttributes keepAttributes, ProguardClassFilter keepPackageNamesPatterns, @@ -474,7 +466,6 @@ this.printMapping = printMapping; this.printMappingFile = printMappingFile; this.applyMappingFile = applyMappingFile; - this.verbose = verbose; this.renameSourceFileAttribute = renameSourceFileAttribute; this.keepAttributes = keepAttributes; this.keepPackageNamesPatterns = keepPackageNamesPatterns; @@ -581,10 +572,6 @@ return printUsageFile; } - public boolean isVerbose() { - return verbose; - } - public String getRenameSourceFileAttribute() { return renameSourceFileAttribute; }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java index 8c6aa57..95e0fde 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -84,7 +84,8 @@ "allowruntypeandignoreoptimizationpasses", "dontshrinkduringoptimization", "convert_proto_enum_to_string", - "adaptkotlinmetadata"); + "adaptkotlinmetadata", + "verbose"); private static final List<String> IGNORED_CLASS_DESCRIPTOR_OPTIONS = ImmutableList.of("isclassnamestring", "whyarenotsimple"); @@ -364,8 +365,6 @@ } } else if (acceptString("shrinkunusedprotofields")) { configurationBuilder.enableProtoShrinking(); - } else if (acceptString("verbose")) { - configurationBuilder.setVerbose(true); } else if (acceptString("ignorewarnings")) { configurationBuilder.setIgnoreWarnings(true); } else if (acceptString("dontwarn")) {
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java index 4740a7c..1165be4 100644 --- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java +++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -465,7 +465,8 @@ Entry entry = entryWrapper.getEntry(); int entryId = entryWrapper.getId(); recordSingleValueResources(resourceType, entry, entryId); - if (resourceType != ResourceType.STYLEABLE || includeStyleables) { + if (resourceType != null + && (resourceType != ResourceType.STYLEABLE || includeStyleables)) { this.addResource( resourceType, entryWrapper.getPackageName(),
diff --git a/src/test/examplesJava17/records/RecordBlogTest.java b/src/test/examplesJava17/records/RecordBlogTest.java index 1128f07..37f1117 100644 --- a/src/test/examplesJava17/records/RecordBlogTest.java +++ b/src/test/examplesJava17/records/RecordBlogTest.java
@@ -57,7 +57,7 @@ private boolean isCfRuntimeWithNativeRecordSupport() { return parameters.isCfRuntime() - && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) + && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17) && parameters.getApiLevel().equals(AndroidApiLevel.B); }
diff --git a/src/test/examplesJava17/records/RecordHashCodeManyFieldsTest.java b/src/test/examplesJava17/records/RecordHashCodeManyFieldsTest.java index 6c2a31b..1cd7313 100644 --- a/src/test/examplesJava17/records/RecordHashCodeManyFieldsTest.java +++ b/src/test/examplesJava17/records/RecordHashCodeManyFieldsTest.java
@@ -37,7 +37,7 @@ private boolean isCfRuntimeWithNativeRecordSupport() { return parameters.isCfRuntime() - && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) + && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17) && parameters.getApiLevel().equals(AndroidApiLevel.B); }
diff --git a/src/test/examplesJava17/records/RecordHashCodeTest.java b/src/test/examplesJava17/records/RecordHashCodeTest.java index b0b0b0e..b5a21f4 100644 --- a/src/test/examplesJava17/records/RecordHashCodeTest.java +++ b/src/test/examplesJava17/records/RecordHashCodeTest.java
@@ -37,7 +37,7 @@ private boolean isCfRuntimeWithNativeRecordSupport() { return parameters.isCfRuntime() - && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) + && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17) && parameters.getApiLevel().equals(AndroidApiLevel.B); }
diff --git a/src/test/examplesJava17/records/RecordInterfaceTest.java b/src/test/examplesJava17/records/RecordInterfaceTest.java index d5144b0..583ccb4 100644 --- a/src/test/examplesJava17/records/RecordInterfaceTest.java +++ b/src/test/examplesJava17/records/RecordInterfaceTest.java
@@ -48,7 +48,7 @@ private boolean isCfRuntimeWithNativeRecordSupport() { return parameters.isCfRuntime() - && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) + && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17) && parameters.getApiLevel().equals(AndroidApiLevel.B); }
diff --git a/src/test/examplesJava17/records/RecordInvokeCustomTest.java b/src/test/examplesJava17/records/RecordInvokeCustomTest.java index ec3956a..55c9d9c 100644 --- a/src/test/examplesJava17/records/RecordInvokeCustomTest.java +++ b/src/test/examplesJava17/records/RecordInvokeCustomTest.java
@@ -4,18 +4,17 @@ package records; +import com.android.tools.r8.JdkClassFileProvider; import com.android.tools.r8.R8FullTestBuilder; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRuntime.CfRuntime; import com.android.tools.r8.TestRuntime.CfVm; -import com.android.tools.r8.desugar.LibraryFilesHelper; import com.android.tools.r8.utils.StringUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import records.RecordInvokeCustom.Empty; -import records.RecordInvokeCustom.Person; @RunWith(Parameterized.class) public class RecordInvokeCustomTest extends TestBase { @@ -83,7 +82,9 @@ .addKeepMainRule(RecordInvokeCustom.class); if (parameters.isCfRuntime()) { builder - .addLibraryFiles(LibraryFilesHelper.getJdk15LibraryFiles(temp)) + .addLibraryProvider( + JdkClassFileProvider.fromSystemModulesJdk( + CfRuntime.getCheckedInJdk17().getJavaHome())) .compile() .inspect(RecordTestUtils::assertRecordsAreRecords) .run(parameters.getRuntime(), RecordInvokeCustom.class)
diff --git a/src/test/examplesJava17/records/SimpleRecordTest.java b/src/test/examplesJava17/records/SimpleRecordTest.java index d7c8131..cfedd02 100644 --- a/src/test/examplesJava17/records/SimpleRecordTest.java +++ b/src/test/examplesJava17/records/SimpleRecordTest.java
@@ -47,7 +47,7 @@ private boolean isCfRuntimeWithNativeRecordSupport() { return parameters.isCfRuntime() - && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) + && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17) && parameters.getApiLevel().equals(AndroidApiLevel.B); }
diff --git a/src/test/java/com/android/tools/r8/androidresources/SyntheticResourceTypeTest.java b/src/test/java/com/android/tools/r8/androidresources/SyntheticResourceTypeTest.java new file mode 100644 index 0000000..39f81a6 --- /dev/null +++ b/src/test/java/com/android/tools/r8/androidresources/SyntheticResourceTypeTest.java
@@ -0,0 +1,88 @@ +// Copyright (c) 2025, 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.androidresources; + +import com.android.aapt.Resources.ResourceTable; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource; +import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class SyntheticResourceTypeTest extends TestBase { + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection parameters() { + return getTestParameters().withDefaultDexRuntime().withAllApiLevels().build(); + } + + public static AndroidTestResource getTestResources(TemporaryFolder temp) throws Exception { + return new AndroidTestResourceBuilder() + .withSimpleManifestAndAppNameString() + .addRClassInitializeWithDefaultValues(R.drawable.class) + .build(temp) + .mangleResourceTable( + resourceTable -> { + // We are adding a synthetic type that we can't easily get aapt2 to generate. + // Explicitly build the entry using the resource table builder. + ResourceTable.Builder resourceTableBuilder = resourceTable.toBuilder(); + resourceTableBuilder + .getPackageBuilderList() + .get(0) + .addTypeBuilder() + .setName("macro") + .addEntryBuilder() + .setName("macro_name") + .addConfigValueBuilder() + .getValueBuilder() + .getItemBuilder() + .getStrBuilder() + .setValue("macro_value") + .build(); + return resourceTableBuilder.build(); + }); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(FooBar.class) + .addAndroidResources(getTestResources(temp)) + .addKeepMainRule(FooBar.class) + .enableOptimizedShrinking() + .compile() + .inspectShrunkenResources( + resourceTableInspector -> { + resourceTableInspector.assertContainsResourceWithName("drawable", "foo"); + // The synthetic macro entries should not be touched by the resource shrinker. + resourceTableInspector.assertContainsResourceWithName("macro", "macro_name"); + resourceTableInspector.assertDoesNotContainResourceWithName("drawable", "bar"); + }); + } + + public static class FooBar { + public static void main(String[] args) { + System.out.println(R.drawable.foo); + } + } + + public static class R { + public static class drawable { + public static int foo; + public static int bar; + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AndroidOsBuildVersionCodesFullBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AndroidOsBuildVersionCodesFullBackportTest.java index 1c9e1a0..c5ca271 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/AndroidOsBuildVersionCodesFullBackportTest.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/AndroidOsBuildVersionCodesFullBackportTest.java
@@ -13,9 +13,13 @@ import com.android.tools.r8.transformers.ClassFileTransformer; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.lang.reflect.Field; +import org.junit.Assert; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @@ -85,85 +89,153 @@ .transform(); } + @Test + public void checkVersionCodesFullInAndroidJar() throws Exception { + ClassSubject versionCodesFullClass = + new CodeInspector(parameters.getDefaultAndroidJar()) + .clazz("android.os.Build$VERSION_CODES_FULL"); + Assert.assertFalse(versionCodesFullClass.isPresent()); + // Update test when fully testing Android Baklava. + Assert.assertFalse(parameters.getApiLevel().equals(AndroidApiLevel.BAKLAVA)); + if (parameters.getApiLevel().equals(AndroidApiLevel.V)) { + versionCodesFullClass = + new CodeInspector(ToolHelper.getAndroidJar(AndroidApiLevel.BAKLAVA)) + .clazz("android.os.Build$VERSION_CODES_FULL"); + Assert.assertTrue(versionCodesFullClass.isPresent()); + // Update test when more version codes full are added. + Assert.assertEquals(35, versionCodesFullClass.allFields().size()); + // Copied from BackportedMethodRewriter. + Object[][] versionCodesFull = { + {"BASE", 100_000}, + {"BASE_1_1", 200_000}, + {"CUPCAKE", 300_000}, + {"DONUT", 400_000}, + {"ECLAIR", 500_000}, + {"ECLAIR_0_1", 600_000}, + {"ECLAIR_MR1", 700_000}, + {"FROYO", 800_000}, + {"GINGERBREAD", 900_000}, + {"GINGERBREAD_MR1", 1000_000}, + {"HONEYCOMB", 1100_000}, + {"HONEYCOMB_MR1", 1200_000}, + {"HONEYCOMB_MR2", 1300_000}, + {"ICE_CREAM_SANDWICH", 1400_000}, + {"ICE_CREAM_SANDWICH_MR1", 1500_000}, + {"JELLY_BEAN", 1600_000}, + {"JELLY_BEAN_MR1", 1700_000}, + {"JELLY_BEAN_MR2", 1800_000}, + {"KITKAT", 1900_000}, + {"KITKAT_WATCH", 2000_000}, + {"LOLLIPOP", 2100_000}, + {"LOLLIPOP_MR1", 2200_000}, + {"M", 2300_000}, + {"N", 2400_000}, + {"N_MR1", 2500_000}, + {"O", 2600_000}, + {"O_MR1", 2700_000}, + {"P", 2800_000}, + {"Q", 2900_000}, + {"R", 3000_000}, + {"S", 3100_000}, + {"S_V2", 3200_000}, + {"TIRAMISU", 3300_000}, + {"UPSIDE_DOWN_CAKE", 3400_000}, + {"VANILLA_ICE_CREAM", 3500_000}, + }; + for (Object[] versionCodeFull : versionCodesFull) { + Assert.assertEquals( + ((Integer) versionCodeFull[1]).intValue(), + versionCodesFullClass + .field("int", (String) versionCodeFull[0]) + .getField() + .getStaticValue() + .asDexValueInt() + .value); + } + } + } + // android.os.Build$VERSION_CODES_FULL for building TestRunner and for runtime classpath. - // Fields are not final to insure that the static gets are not inlined by javac for the test code. + // Fields are not final to ensure that the static gets are not inlined by javac for the test code + // and the field values are not relevant, as desugaring will replace them with the proper + // constants. public static class /*android.os.Build$*/ VERSION_CODES_FULL { - public static /* final */ int BASE = 10_000; - public static /* final */ int BASE_1_1 = 20_000; - public static /* final */ int CUPCAKE = 30_000; - public static /* final */ int DONUT = 40_000; - public static /* final */ int ECLAIR = 50_000; - public static /* final */ int ECLAIR_0_1 = 60_000; - public static /* final */ int ECLAIR_MR1 = 70_000; - public static /* final */ int FROYO = 80_000; - public static /* final */ int GINGERBREAD = 90_000; - public static /* final */ int GINGERBREAD_MR1 = 100_000; - public static /* final */ int HONEYCOMB = 110_000; - public static /* final */ int HONEYCOMB_MR1 = 120_000; - public static /* final */ int HONEYCOMB_MR2 = 130_000; - public static /* final */ int ICE_CREAM_SANDWICH = 140_000; - public static /* final */ int ICE_CREAM_SANDWICH_MR1 = 150_000; - public static /* final */ int JELLY_BEAN = 160_000; - public static /* final */ int JELLY_BEAN_MR1 = 170_000; - public static /* final */ int JELLY_BEAN_MR2 = 180_000; - public static /* final */ int KITKAT = 190_000; - public static /* final */ int KITKAT_WATCH = 200_000; - public static /* final */ int LOLLIPOP = 210_000; - public static /* final */ int LOLLIPOP_MR1 = 220_000; - public static /* final */ int M = 230_000; - public static /* final */ int N = 240_000; - public static /* final */ int N_MR1 = 250_000; - public static /* final */ int O = 260_000; - public static /* final */ int O_MR1 = 270_000; - public static /* final */ int P = 280_000; - public static /* final */ int Q = 290_000; - public static /* final */ int R = 300_000; - public static /* final */ int S = 310_000; - public static /* final */ int S_V2 = 320_000; - public static /* final */ int TIRAMISU = 330_000; - public static /* final */ int UPSIDE_DOWN_CAKE = 340_000; - public static /* final */ int VANILLA_ICE_CREAM = 350_000; + public static /* final */ int BASE = -1; + public static /* final */ int BASE_1_1 = -1; + public static /* final */ int CUPCAKE = -1; + public static /* final */ int DONUT = -1; + public static /* final */ int ECLAIR = -1; + public static /* final */ int ECLAIR_0_1 = -1; + public static /* final */ int ECLAIR_MR1 = -1; + public static /* final */ int FROYO = -1; + public static /* final */ int GINGERBREAD = -1; + public static /* final */ int GINGERBREAD_MR1 = -1; + public static /* final */ int HONEYCOMB = -1; + public static /* final */ int HONEYCOMB_MR1 = -1; + public static /* final */ int HONEYCOMB_MR2 = -1; + public static /* final */ int ICE_CREAM_SANDWICH = -1; + public static /* final */ int ICE_CREAM_SANDWICH_MR1 = -1; + public static /* final */ int JELLY_BEAN = -1; + public static /* final */ int JELLY_BEAN_MR1 = -1; + public static /* final */ int JELLY_BEAN_MR2 = -1; + public static /* final */ int KITKAT = -1; + public static /* final */ int KITKAT_WATCH = -1; + public static /* final */ int LOLLIPOP = -1; + public static /* final */ int LOLLIPOP_MR1 = -1; + public static /* final */ int M = -1; + public static /* final */ int N = -1; + public static /* final */ int N_MR1 = -1; + public static /* final */ int O = -1; + public static /* final */ int O_MR1 = -1; + public static /* final */ int P = -1; + public static /* final */ int Q = -1; + public static /* final */ int R = -1; + public static /* final */ int S = -1; + public static /* final */ int S_V2 = -1; + public static /* final */ int TIRAMISU = -1; + public static /* final */ int UPSIDE_DOWN_CAKE = -1; + public static /* final */ int VANILLA_ICE_CREAM = -1; } public static class TestRunner extends MiniAssert { public static void main(String[] args) throws Exception { - assertEquals(10_000, VERSION_CODES_FULL.BASE); - assertEquals(20_000, VERSION_CODES_FULL.BASE_1_1); - assertEquals(30_000, VERSION_CODES_FULL.CUPCAKE); - assertEquals(40_000, VERSION_CODES_FULL.DONUT); - assertEquals(50_000, VERSION_CODES_FULL.ECLAIR); - assertEquals(60_000, VERSION_CODES_FULL.ECLAIR_0_1); - assertEquals(70_000, VERSION_CODES_FULL.ECLAIR_MR1); - assertEquals(80_000, VERSION_CODES_FULL.FROYO); - assertEquals(90_000, VERSION_CODES_FULL.GINGERBREAD); - assertEquals(100_000, VERSION_CODES_FULL.GINGERBREAD_MR1); - assertEquals(110_000, VERSION_CODES_FULL.HONEYCOMB); - assertEquals(120_000, VERSION_CODES_FULL.HONEYCOMB_MR1); - assertEquals(130_000, VERSION_CODES_FULL.HONEYCOMB_MR2); - assertEquals(140_000, VERSION_CODES_FULL.ICE_CREAM_SANDWICH); - assertEquals(150_000, VERSION_CODES_FULL.ICE_CREAM_SANDWICH_MR1); - assertEquals(160_000, VERSION_CODES_FULL.JELLY_BEAN); - assertEquals(170_000, VERSION_CODES_FULL.JELLY_BEAN_MR1); - assertEquals(180_000, VERSION_CODES_FULL.JELLY_BEAN_MR2); - assertEquals(190_000, VERSION_CODES_FULL.KITKAT); - assertEquals(200_000, VERSION_CODES_FULL.KITKAT_WATCH); - assertEquals(210_000, VERSION_CODES_FULL.LOLLIPOP); - assertEquals(220_000, VERSION_CODES_FULL.LOLLIPOP_MR1); - assertEquals(230_000, VERSION_CODES_FULL.M); - assertEquals(240_000, VERSION_CODES_FULL.N); - assertEquals(250_000, VERSION_CODES_FULL.N_MR1); - assertEquals(260_000, VERSION_CODES_FULL.O); - assertEquals(270_000, VERSION_CODES_FULL.O_MR1); - assertEquals(280_000, VERSION_CODES_FULL.P); - assertEquals(290_000, VERSION_CODES_FULL.Q); - assertEquals(300_000, VERSION_CODES_FULL.R); - assertEquals(310_000, VERSION_CODES_FULL.S); - assertEquals(320_000, VERSION_CODES_FULL.S_V2); - assertEquals(330_000, VERSION_CODES_FULL.TIRAMISU); - assertEquals(340_000, VERSION_CODES_FULL.UPSIDE_DOWN_CAKE); - assertEquals(350_000, VERSION_CODES_FULL.VANILLA_ICE_CREAM); + assertEquals(100_000, VERSION_CODES_FULL.BASE); + assertEquals(200_000, VERSION_CODES_FULL.BASE_1_1); + assertEquals(300_000, VERSION_CODES_FULL.CUPCAKE); + assertEquals(400_000, VERSION_CODES_FULL.DONUT); + assertEquals(500_000, VERSION_CODES_FULL.ECLAIR); + assertEquals(600_000, VERSION_CODES_FULL.ECLAIR_0_1); + assertEquals(700_000, VERSION_CODES_FULL.ECLAIR_MR1); + assertEquals(800_000, VERSION_CODES_FULL.FROYO); + assertEquals(900_000, VERSION_CODES_FULL.GINGERBREAD); + assertEquals(1000_000, VERSION_CODES_FULL.GINGERBREAD_MR1); + assertEquals(1100_000, VERSION_CODES_FULL.HONEYCOMB); + assertEquals(1200_000, VERSION_CODES_FULL.HONEYCOMB_MR1); + assertEquals(1300_000, VERSION_CODES_FULL.HONEYCOMB_MR2); + assertEquals(1400_000, VERSION_CODES_FULL.ICE_CREAM_SANDWICH); + assertEquals(1500_000, VERSION_CODES_FULL.ICE_CREAM_SANDWICH_MR1); + assertEquals(1600_000, VERSION_CODES_FULL.JELLY_BEAN); + assertEquals(1700_000, VERSION_CODES_FULL.JELLY_BEAN_MR1); + assertEquals(1800_000, VERSION_CODES_FULL.JELLY_BEAN_MR2); + assertEquals(1900_000, VERSION_CODES_FULL.KITKAT); + assertEquals(2000_000, VERSION_CODES_FULL.KITKAT_WATCH); + assertEquals(2100_000, VERSION_CODES_FULL.LOLLIPOP); + assertEquals(2200_000, VERSION_CODES_FULL.LOLLIPOP_MR1); + assertEquals(2300_000, VERSION_CODES_FULL.M); + assertEquals(2400_000, VERSION_CODES_FULL.N); + assertEquals(2500_000, VERSION_CODES_FULL.N_MR1); + assertEquals(2600_000, VERSION_CODES_FULL.O); + assertEquals(2700_000, VERSION_CODES_FULL.O_MR1); + assertEquals(2800_000, VERSION_CODES_FULL.P); + assertEquals(2900_000, VERSION_CODES_FULL.Q); + assertEquals(3000_000, VERSION_CODES_FULL.R); + assertEquals(3100_000, VERSION_CODES_FULL.S); + assertEquals(3200_000, VERSION_CODES_FULL.S_V2); + assertEquals(3300_000, VERSION_CODES_FULL.TIRAMISU); + assertEquals(3400_000, VERSION_CODES_FULL.UPSIDE_DOWN_CAKE); + assertEquals(3500_000, VERSION_CODES_FULL.VANILLA_ICE_CREAM); } } }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerCoalescingAfterSplitReturnRewriterTest.java b/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerCoalescingAfterSplitReturnRewriterTest.java index 6ea9c73..fa241ae 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerCoalescingAfterSplitReturnRewriterTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerCoalescingAfterSplitReturnRewriterTest.java
@@ -51,8 +51,7 @@ assertThat(testMethodSubject, isPresent()); DexCode code = testMethodSubject.getMethod().getCode().asDexCode(); - // TODO(b/384848525): Should be 1. - assertEquals(forceSplitReturnRewriter ? 2 : 1, code.getTries().length); + assertEquals(1, code.getTries().length); }); } @@ -63,6 +62,7 @@ doStuff(); doStuff(); } catch (Exception e) { + System.out.println(e); return e; } return null;
diff --git a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java index 241c2f3..4af8c94 100644 --- a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
@@ -85,7 +85,7 @@ .run(parameters.getRuntime(), TestClass.class) .applyIf( // No default JS engine starting from JDK-14 where Nashorn was removed, see b/227162584. - parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14), + parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17), r -> r.assertFailureWithErrorThatThrows(NullPointerException.class), r -> r.assertSuccessWithOutput(
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java index a8e80aa..6865487 100644 --- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
@@ -115,7 +115,7 @@ parameters.isCfRuntime() // No default JS engine starting from JDK-14 where Nashorn was removed, // see b/227162584. - ? (parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) + ? (parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17) ? StringUtils.lines("MyEngine1", "MyEngine2") : StringUtils.lines("MyEngine1", "MyEngine2", "Oracle Nashorn")) : StringUtils.lines("Mozilla Rhino", "MyEngine1", "MyEngine2"));
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java index c94ce9c..ad664d3 100644 --- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java +++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -1058,8 +1058,6 @@ new ProguardConfigurationParser(new DexItemFactory(), reporter); parser.parse(Paths.get(VERBOSE)); verifyParserEndsCleanly(); - ProguardConfiguration config = parser.getConfig(); - assertTrue(config.isVerbose()); } @Test
diff --git a/src/test/testbase/java/com/android/tools/r8/TestRuntime.java b/src/test/testbase/java/com/android/tools/r8/TestRuntime.java index f14cec1..889f7a3 100644 --- a/src/test/testbase/java/com/android/tools/r8/TestRuntime.java +++ b/src/test/testbase/java/com/android/tools/r8/TestRuntime.java
@@ -35,11 +35,6 @@ JDK9("jdk9", 53), JDK10("jdk10", 54), JDK11("jdk11", 55), - JDK12("jdk12", 56), - JDK13("jdk13", 57), - JDK14("jdk14", 58), - JDK15("jdk15", 59), - JDK16("jdk16", 60), JDK17("jdk17", 61), JDK18("jdk18", 62), JDK20("jdk20", 64),
diff --git a/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java b/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java index 92e0618..d55db2f 100644 --- a/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java +++ b/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
@@ -32,6 +32,7 @@ import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collection; @@ -42,6 +43,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -175,7 +177,7 @@ public static class AndroidTestResource { private final AndroidTestRClass rClass; - private final Path resourceZip; + private Path resourceZip; private final List<String> additionalKeepRuleFiles; AndroidTestResource( @@ -185,6 +187,28 @@ this.additionalKeepRuleFiles = additionalRawXmlFiles; } + public AndroidTestResource mangleResourceTable(Function<ResourceTable, ResourceTable> mapper) + throws IOException { + Path newName = Paths.get(resourceZip.toString() + ".mangled.ap_"); + ZipUtils.map( + resourceZip, + newName, + (zipEntry, bytes) -> { + if (zipEntry.getName().equals("resources.pb")) { + try { + ResourceTable resourceTable = ResourceTable.parseFrom(bytes); + ResourceTable converted = mapper.apply(resourceTable); + return converted.toByteArray(); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + } + return bytes; + }); + resourceZip = newName; + return this; + } + public AndroidTestRClass getRClass() { return rClass; }
diff --git a/src/test/testbase/java/com/android/tools/r8/desugar/LibraryFilesHelper.java b/src/test/testbase/java/com/android/tools/r8/desugar/LibraryFilesHelper.java index 0a605cb..a618531 100644 --- a/src/test/testbase/java/com/android/tools/r8/desugar/LibraryFilesHelper.java +++ b/src/test/testbase/java/com/android/tools/r8/desugar/LibraryFilesHelper.java
@@ -39,48 +39,6 @@ return getJdk9LibraryFiles(temp); } - public static Path[] getJdk15LibraryFiles(TemporaryFolder temp) throws Exception { - // TODO(b/270105162): We should be able to run this on windows. - Assume.assumeFalse(ToolHelper.isWindows()); - // TODO(b/169645628): Add JDK-15 runtime jar instead. As a temporary solution we use the jdk 8 - // runtime with additional stubs. - Path generatedJar = temp.newFolder().toPath().resolve("stubs.jar"); - ZipBuilder builder = ZipBuilder.builder(generatedJar); - addRecord(builder); - addRecordComponent(builder); - addObjectsMethod(builder); - addTypeDescriptor(builder); - builder.build(); - return ObjectArrays.concat(getJdk9LibraryFiles(temp), new Path[] {generatedJar}, Path.class); - } - - // Generates a class file for: - // <pre> - // public class ObjectMethods {} - // </pre> - private static void addObjectsMethod(ZipBuilder builder) throws Exception { - addClassToZipBuilder( - builder, ACC_PUBLIC, "java/lang/runtime/ObjectMethods", ConsumerUtils.emptyConsumer()); - } - - // Generates a class file for: - // <pre> - // public interface TypeDescriptor { - // String descriptorString(); - // } - // </pre> - private static void addTypeDescriptor(ZipBuilder builder) throws Exception { - addClassToZipBuilder( - builder, - ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, - "java/lang/invoke/TypeDescriptor", - methodAdder -> - methodAdder.add( - ACC_PUBLIC | ACC_ABSTRACT, - "descriptorString", - methodDescriptor(false, String.class))); - } - // Generates a class file for: // <pre> // public class StringConcatFactory {} @@ -101,45 +59,6 @@ // Generates a class file for: // <pre> - // public abstract class Record { - // protected Record() {} - // - // public abstract boolean equals(Object obj); - // - // public abstract int hashCode(); - // - // public abstract String toString(); - // } - // </pre> - private static void addRecord(ZipBuilder builder) throws Exception { - addClassToZipBuilder( - builder, - ACC_PUBLIC | ACC_ABSTRACT, - "java/lang/Record", - methodAdder -> { - methodAdder.add(ACC_PROTECTED, "<init>", "()V"); - methodAdder.add( - ACC_PUBLIC | ACC_ABSTRACT, - "equals", - methodDescriptor(false, Object.class, boolean.class)); - methodAdder.add( - ACC_PUBLIC | ACC_ABSTRACT, "hashCode", methodDescriptor(false, int.class)); - methodAdder.add( - ACC_PUBLIC | ACC_ABSTRACT, "toString", methodDescriptor(false, String.class)); - }); - } - - // Generates a class file for: - // <pre> - // public class RecordComponent {} - // </pre> - private static void addRecordComponent(ZipBuilder builder) throws Exception { - addClassToZipBuilder( - builder, ACC_PUBLIC, "java/lang/reflect/RecordComponent", ConsumerUtils.emptyConsumer()); - } - - // Generates a class file for: - // <pre> // public interface Supplier { // Object get(); // }
diff --git a/tools/jdk.py b/tools/jdk.py index d795230..86f2c3a 100755 --- a/tools/jdk.py +++ b/tools/jdk.py
@@ -10,8 +10,7 @@ JDK_DIR = os.path.join(defines.THIRD_PARTY, 'openjdk') -ALL_JDKS = ['openjdk-9.0.4', 'jdk-11', 'jdk-15', 'jdk-16', 'jdk-17', - 'jdk-18', 'jdk-21', 'jdk-23'] +ALL_JDKS = ['openjdk-9.0.4', 'jdk-11', 'jdk-17', 'jdk-21', 'jdk-23'] def GetJdkHome():