Merge "Only run MethodHandleTest on DexVm.ART_DEFAULT"
diff --git a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
index e46bef9..5b96201 100644
--- a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
+++ b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
@@ -18,11 +18,19 @@
*
* <p>Lines with a # prefix are ignored.
*
- * <p>We will do most specific matching, i.e., com.google.foobar.*:feature2 com.google.*:base will
- * put everything in the com.google namespace into base, except classes in com.google.foobar that
- * will go to feature2. Class based mappings takes precedence over packages (since they are more
- * specific): com.google.A:feature2 com.google.*:base Puts A into feature2, and all other classes
- * from com.google into base.
+ * <p>We will do most specific matching, i.e.,
+ * <pre>
+ * com.google.foobar.*:feature2
+ * com.google.*:base
+ * </pre>
+ * will put everything in the com.google namespace into base, except classes in com.google.foobar
+ * that will go to feature2. Class based mappings takes precedence over packages (since they are
+ * more specific):
+ * <pre>
+ * com.google.A:feature2
+ * com.google.*:base
+ * </pre>
+ * Puts A into feature2, and all other classes from com.google into base.
*
* <p>Note that this format does not allow specifying inter-module dependencies, this is simply a
* placement tool.
@@ -32,10 +40,12 @@
HashMap<String, String> parsedRules = new HashMap<>(); // Already parsed rules.
HashSet<FeaturePredicate> mappings = new HashSet<>();
+
Path mappingFile;
static final String COMMENT = "#";
static final String SEPARATOR = ":";
+ static final String BASE_NAME = "base";
public static FeatureClassMapping fromSpecification(Path file)
throws FeatureMappingException, IOException {
@@ -69,7 +79,7 @@
private FeatureClassMapping() {}
- public void addMapping(String clazz, String feature) throws FeatureMappingException {
+ private void addMapping(String clazz, String feature) throws FeatureMappingException {
addRule(clazz, feature, 0);
}
@@ -91,7 +101,7 @@
}
}
if (bestMatch == null) {
- throw new FeatureMappingException("Class: " + clazz + " is not mapped to any feature");
+ return BASE_NAME;
}
return bestMatch.feature;
}
diff --git a/src/test/examples/dexsplitsample/Class1.java b/src/test/examplesAndroidN/dexsplitsample/Class1.java
similarity index 100%
rename from src/test/examples/dexsplitsample/Class1.java
rename to src/test/examplesAndroidN/dexsplitsample/Class1.java
diff --git a/src/test/examples/dexsplitsample/Class2.java b/src/test/examplesAndroidN/dexsplitsample/Class2.java
similarity index 100%
rename from src/test/examples/dexsplitsample/Class2.java
rename to src/test/examplesAndroidN/dexsplitsample/Class2.java
diff --git a/src/test/examples/dexsplitsample/Class3.java b/src/test/examplesAndroidN/dexsplitsample/Class3.java
similarity index 100%
rename from src/test/examples/dexsplitsample/Class3.java
rename to src/test/examplesAndroidN/dexsplitsample/Class3.java
diff --git a/src/test/examplesAndroidN/dexsplitsample/Class4.java b/src/test/examplesAndroidN/dexsplitsample/Class4.java
new file mode 100644
index 0000000..5b1607f
--- /dev/null
+++ b/src/test/examplesAndroidN/dexsplitsample/Class4.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package dexsplitsample;
+
+public class Class4 {
+ public static void main(String[] args) {
+ new Class4().createLambda();
+ System.out.println("Class4");
+ }
+
+ private void useLambda(LambdaInterface toInvokeOn) {
+ toInvokeOn.foo(42);
+ }
+
+ private void createLambda() {
+ useLambda((a) -> { return a + 2;});
+ }
+
+ interface LambdaInterface {
+ int foo(int a);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
index 43e9d03..19a5ee2 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
@@ -40,11 +41,15 @@
public class DexSplitterTests {
- private static final String CLASS_DIR = ToolHelper.EXAMPLES_BUILD_DIR + "classes/dexsplitsample";
+ private static final String CLASS_DIR =
+ ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR + "classes/dexsplitsample";
private static final String CLASS1_CLASS = CLASS_DIR + "/Class1.class";
private static final String CLASS2_CLASS = CLASS_DIR + "/Class2.class";
private static final String CLASS3_CLASS = CLASS_DIR + "/Class3.class";
private static final String CLASS3_INNER_CLASS = CLASS_DIR + "/Class3$InnerClass.class";
+ private static final String CLASS4_CLASS = CLASS_DIR + "/Class4.class";
+ private static final String CLASS4_LAMBDA_INTERFACE = CLASS_DIR + "/Class4$LambdaInterface.class";
+
@Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@@ -75,6 +80,8 @@
.addProgramFiles(Paths.get(CLASS2_CLASS))
.addProgramFiles(Paths.get(CLASS3_CLASS))
.addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
+ .addProgramFiles(Paths.get(CLASS4_CLASS))
+ .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
.build());
Path output = temp.getRoot().toPath().resolve("output");
@@ -135,6 +142,18 @@
} catch (AssertionError assertionError) {
// We expect this to throw since base is not in the path and Class3 depends on Class1
}
+
+ className = "Class4";
+ builder = new ArtCommandBuilder();
+ builder.appendClasspath(feature.toString());
+ builder.setMainClass("dexsplitsample." + className);
+ try {
+ ToolHelper.runArt(builder);
+ assertFalse(true);
+ } catch (AssertionError assertionError) {
+ // We expect this to throw since base is not in the path and Class4 includes a lambda that
+ // would have been pushed to base.
+ }
}
private Path createSplitSpec() throws FileNotFoundException, UnsupportedEncodingException {
@@ -143,7 +162,8 @@
out.write(
"dexsplitsample.Class1:base\n"
+ "dexsplitsample.Class2:feature1\n"
- + "dexsplitsample.Class3:feature1");
+ + "dexsplitsample.Class3:feature1\n"
+ + "dexsplitsample.Class4:feature1");
}
return splitSpec;
}
@@ -159,11 +179,13 @@
public void splitFilesFromJar()
throws IOException, CompilationFailedException, FeatureMappingException, ResourceException,
CompilationException, ExecutionException {
- splitFromJars(true);
- splitFromJars(false);
+ splitFromJars(true, true);
+ splitFromJars(false, true);
+ splitFromJars(true, false);
+ splitFromJars(false, false);
}
- private void splitFromJars(boolean useOptions)
+ private void splitFromJars(boolean useOptions, boolean explicitBase)
throws IOException, CompilationFailedException, FeatureMappingException, ResourceException,
ExecutionException, CompilationException {
// Initial normal compile to create dex files.
@@ -175,6 +197,8 @@
.addProgramFiles(Paths.get(CLASS2_CLASS))
.addProgramFiles(Paths.get(CLASS3_CLASS))
.addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
+ .addProgramFiles(Paths.get(CLASS4_CLASS))
+ .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
.build());
Path output = temp.getRoot().toPath().resolve("output");
@@ -200,26 +224,38 @@
featureStream.putNextEntry(new ZipEntry(name));
featureStream.write(Files.readAllBytes(Paths.get(CLASS3_INNER_CLASS)));
featureStream.closeEntry();
+ name = "dexsplitsample/Class4";
+ featureStream.putNextEntry(new ZipEntry(name));
+ featureStream.write(Files.readAllBytes(Paths.get(CLASS4_CLASS)));
+ featureStream.closeEntry();
+ name = "dexsplitsample/Class4$LambdaInterface";
+ featureStream.putNextEntry(new ZipEntry(name));
+ featureStream.write(Files.readAllBytes(Paths.get(CLASS4_LAMBDA_INTERFACE)));
+ featureStream.closeEntry();
featureStream.close();
if (useOptions) {
Options options = new Options();
options.inputArchives.add(inputZip.toString());
options.splitBaseName = output.toString();
- options.featureJars.add(baseJar.toString());
+ if (explicitBase) {
+ options.featureJars.add(baseJar.toString());
+ }
options.featureJars.add(featureJar.toString());
DexSplitter.run(options);
} else {
- DexSplitter.main(
- new String[]{
- "--input",
- inputZip.toString(),
- "--output",
- output.toString(),
- "--feature-jar",
- baseJar.toString(),
- "--feature-jar",
- featureJar.toString()
- });
+ List<String> args = Lists.newArrayList(
+ "--input",
+ inputZip.toString(),
+ "--output",
+ output.toString(),
+ "--feature-jar",
+ featureJar.toString());
+ if (explicitBase) {
+ args.add("--feature-jar");
+ args.add(baseJar.toString());
+ }
+
+ DexSplitter.main(args.toArray(new String[0]));
}
Path base = output.getParent().resolve("output.base.zip");
Path feature = output.getParent().resolve("output.feature1.zip");
@@ -241,6 +277,8 @@
.addProgramFiles(Paths.get(CLASS2_CLASS))
.addProgramFiles(Paths.get(CLASS3_CLASS))
.addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
+ .addProgramFiles(Paths.get(CLASS4_CLASS))
+ .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.setProguardMapOutputPath(proguardMap)
.addProguardConfiguration(getProguardConf(), null)
diff --git a/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java b/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java
index a8ead8a..eff632a 100644
--- a/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java
+++ b/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java
@@ -65,10 +65,30 @@
@Test
public void testCatchAllWildcards() throws Exception {
+ testBaseWildcard(true);
+ testBaseWildcard(false);
+ testNonBaseCatchAll();
+ }
+
+ private void testNonBaseCatchAll() throws FeatureMappingException {
List<String> lines =
ImmutableList.of(
"com.google.Feature1:feature1",
- "*:base",
+ "*:nonbase",
+ "com.strange.*:feature2");
+ FeatureClassMapping mapping = new FeatureClassMapping(lines);
+ assertEquals(mapping.featureForClass("com.google.Feature1"), "feature1");
+ assertEquals(mapping.featureForClass("com.google.different.Feature1"), "nonbase");
+ assertEquals(mapping.featureForClass("com.strange.different.Feature1"), "feature2");
+ assertEquals(mapping.featureForClass("Feature1"), "nonbase");
+ assertEquals(mapping.featureForClass("a.b.z.A"), "nonbase");
+ }
+
+ private void testBaseWildcard(boolean explicitBase) throws FeatureMappingException {
+ List<String> lines =
+ ImmutableList.of(
+ "com.google.Feature1:feature1",
+ explicitBase ? "*:base" : "",
"com.strange.*:feature2");
FeatureClassMapping mapping = new FeatureClassMapping(lines);
assertEquals(mapping.featureForClass("com.google.Feature1"), "feature1");