Added simple test to compile framework.jar with varying number of internal compilation treads. Added Marker for storing tools information in classes.dex.
Bug:
Change-Id: I53116cf3d796d176d0eae5dc42d92a475bc7c3f2
diff --git a/build.gradle b/build.gradle
index 60357de..e2c21b6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -101,6 +101,7 @@
dependencies {
compile 'net.sf.jopt-simple:jopt-simple:4.6'
+ compile 'com.googlecode.json-simple:json-simple:1.1.1'
compile group: 'com.google.guava', name: 'guava', version: '19.0'
compile group: 'it.unimi.dsi', name: 'fastutil', version: '7.2.0'
compile group: 'org.apache.commons', name: 'commons-compress', version: '1.12'
@@ -397,6 +398,20 @@
}
}
+task ExtractMarker(type: Jar) {
+ from sourceSets.main.output
+ baseName 'extractmarker'
+ manifest {
+ attributes 'Main-Class': 'com.android.tools.r8.ExtractMarker'
+ }
+ // In order to build without dependencies, pass the exclude_deps property using:
+ // gradle -Pexclude_deps ExtractMarker
+ if (!project.hasProperty('exclude_deps')) {
+ // Also include dependencies
+ from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
+ }
+}
+
task sourceJar(type: Jar, dependsOn: classes) {
classifier = 'src'
from sourceSets.main.allSource
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index bca7a9f..a6da2ec 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.ApplicationWriter;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.MainDexError;
import com.android.tools.r8.graph.AppInfo;
@@ -152,6 +154,14 @@
}
}
+ // Compute the marker to be placed in the main dex file.
+ private static Marker getMarker(InternalOptions options) {
+ if (options.customizedMarker != null) {
+ return options.customizedMarker;
+ }
+ return new Marker(Tool.D8);
+ }
+
private static CompilationResult runForTesting(
AndroidApp inputApp, InternalOptions options, ExecutorService executor) throws IOException {
try {
@@ -174,11 +184,11 @@
options.methodsFilter.forEach((m) -> System.out.println(" - " + m));
return null;
}
-
+ Marker marker = getMarker(options);
CompilationResult output =
new CompilationResult(
new ApplicationWriter(
- app, appInfo, options, null, NamingLens.getIdentityLens(), null)
+ app, appInfo, options, marker, null, NamingLens.getIdentityLens(), null)
.write(null, executor),
app,
appInfo);
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
new file mode 100644
index 0000000..c1234b8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -0,0 +1,122 @@
+// Copyright (c) 2017, the Rex 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;
+
+import com.google.common.collect.ImmutableList;
+
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.shaking.ProguardRuleParserException;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OutputMode;
+import com.android.tools.r8.utils.Timing;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.ExecutionException;
+
+public class ExtractMarker {
+ private static class Command extends BaseCommand {
+
+ public static class Builder
+ extends BaseCommand.Builder<ExtractMarker.Command, ExtractMarker.Command.Builder> {
+
+ private Builder() {
+ super(CompilationMode.RELEASE);
+ }
+
+ @Override
+ ExtractMarker.Command.Builder self() {
+ return this;
+ }
+
+ @Override
+ public ExtractMarker.Command build() throws CompilationException, IOException {
+ // If printing versions ignore everything else.
+ if (isPrintHelp()) {
+ return new ExtractMarker.Command(isPrintHelp());
+ }
+ validate();
+ return new ExtractMarker.Command(
+ getAppBuilder().build(), getOutputPath(), getOutputMode(), getMode(), getMinApiLevel());
+ }
+ }
+
+ static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of(
+ "Usage: extractmarker [options] <input-files>",
+ " where <input-files> are dex files",
+ " --version # Print the version of r8.",
+ " --help # Print this message."));
+
+ public static ExtractMarker.Command.Builder builder() {
+ return new ExtractMarker.Command.Builder();
+ }
+
+ public static ExtractMarker.Command.Builder parse(String[] args)
+ throws CompilationException, IOException {
+ ExtractMarker.Command.Builder builder = builder();
+ parse(args, builder);
+ return builder;
+ }
+
+ private static void parse(String[] args, ExtractMarker.Command.Builder builder)
+ throws CompilationException, IOException {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i].trim();
+ if (arg.length() == 0) {
+ continue;
+ } else if (arg.equals("--help")) {
+ builder.setPrintHelp(true);
+ } else {
+ if (arg.startsWith("--")) {
+ throw new CompilationException("Unknown option: " + arg);
+ }
+ builder.addProgramFiles(Paths.get(arg));
+ }
+ }
+ }
+
+ private Command(
+ AndroidApp inputApp,
+ Path outputPath,
+ OutputMode outputMode,
+ CompilationMode mode,
+ int minApiLevel) {
+ super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ }
+
+ private Command(boolean printHelp) {
+ super(printHelp, false);
+ }
+
+ @Override
+ InternalOptions getInternalOptions() {
+ return new InternalOptions();
+ }
+ }
+
+ public static void main(String[] args)
+ throws IOException, ProguardRuleParserException, CompilationException, ExecutionException {
+ ExtractMarker.Command.Builder builder = ExtractMarker.Command.parse(args);
+ ExtractMarker.Command command = builder.build();
+ if (command.isPrintHelp()) {
+ System.out.println(ExtractMarker.Command.USAGE_MESSAGE);
+ return;
+ }
+ AndroidApp app = command.getInputApp();
+ DexApplication dexApp =
+ new ApplicationReader(app, new InternalOptions(), new Timing("ExtractMarker")).read();
+ Marker readMarker = dexApp.dexItemFactory.extractMarker();
+ if (readMarker == null) {
+ System.out.println("D8/R8 marker not found.");
+ System.exit(1);
+ } else {
+ System.out.println(readMarker.toString());
+ System.exit(0);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5f56d79..4393a3e 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.MainDexError;
import com.android.tools.r8.graph.AppInfo;
@@ -77,6 +79,14 @@
options.itemFactory.resetSortedIndices();
}
+ // Compute the marker to be placed in the main dex file.
+ private static Marker getMarker(InternalOptions options) {
+ if (options.customizedMarker != null) {
+ return options.customizedMarker;
+ }
+ return new Marker(Tool.R8);
+ }
+
public static AndroidApp writeApplication(
ExecutorService executorService,
DexApplication application,
@@ -88,8 +98,9 @@
InternalOptions options)
throws ExecutionException {
try {
+ Marker marker = getMarker(options);
return new ApplicationWriter(
- application, appInfo, options, deadCode, namingLens, proguardSeedsData)
+ application, appInfo, options, marker, deadCode, namingLens, proguardSeedsData)
.write(packageDistribution, executorService);
} catch (IOException e) {
throw new RuntimeException("Cannot write dex application", e);
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 4fe3773..ee4477d 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -177,7 +177,7 @@
throws IOException, ExecutionException {
InternalOptions options = new InternalOptions();
AppInfo appInfo = new AppInfo(app);
- ApplicationWriter writer = new ApplicationWriter(app, appInfo, options, null, null, null);
+ ApplicationWriter writer = new ApplicationWriter(app, appInfo, options, null, null, null, null);
AndroidApp outApp = writer.write(null, executor);
outApp.writeToDirectory(output, OutputMode.Indexed);
}
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 1cb0fb0..e6ec968 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.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedArray;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
@@ -43,6 +44,7 @@
public final NamingLens namingLens;
public final byte[] proguardSeedsData;
public final InternalOptions options;
+ public DexString markerString;
private static class SortAnnotations extends MixedSectionCollection {
@@ -105,6 +107,7 @@
DexApplication application,
AppInfo appInfo,
InternalOptions options,
+ Marker marker,
byte[] deadCode,
NamingLens namingLens,
byte[] proguardSeedsData) {
@@ -113,6 +116,9 @@
this.appInfo = appInfo;
assert options != null;
this.options = options;
+ this.markerString = (marker == null)
+ ? null
+ : application.dexItemFactory.createString(marker.toString());
this.deadCode = deadCode;
this.namingLens = namingLens;
this.proguardSeedsData = proguardSeedsData;
@@ -123,6 +129,8 @@
application.timing.begin("DexApplication.write");
try {
application.dexItemFactory.sort(namingLens);
+ assert this.markerString == null || application.dexItemFactory.extractMarker() != null;
+
SortAnnotations sortAnnotations = new SortAnnotations();
application.classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations));
@@ -148,7 +156,8 @@
distributor =
new VirtualFile.PackageMapDistributor(this, packageDistribution, executorService);
} else {
- distributor = new VirtualFile.FillFilesDistributor(this, options.minimalMainDex);
+ boolean minimal = options.minimalMainDex && !application.mainDexList.isEmpty();
+ distributor = new VirtualFile.FillFilesDistributor(this, minimal);
}
Map<Integer, VirtualFile> newFiles = distributor.run();
diff --git a/src/main/java/com/android/tools/r8/dex/Marker.java b/src/main/java/com/android/tools/r8/dex/Marker.java
new file mode 100644
index 0000000..4762fd4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/Marker.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2017, the Rex 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.dex;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+
+/**
+ * Abstraction for hidden dex marker intended for the main dex file.
+ */
+public class Marker {
+
+ public enum Tool {D8, R8}
+
+ private static final String kPrefix = "~~";
+ private static final String kD8prefix = kPrefix + Tool.D8 + "{";
+ private static final String kR8prefix = kPrefix + Tool.R8 + "{";
+
+ private final TreeMap<String, Object> content;
+ private final Tool tool;
+
+ public Marker(Tool tool) {
+ this.tool = tool;
+ this.content = new TreeMap<>();
+ }
+
+ private Marker(Tool tool, JSONObject object) {
+ this.tool = tool;
+ content = new TreeMap<>();
+ // This loop is necessary to make the type checker to shut up.
+ for (Object e : object.entrySet()) {
+ Map.Entry entry = (Map.Entry) e;
+ content.put(String.valueOf(entry.getKey()), entry.getValue());
+ }
+ }
+
+ public Marker put(String key, int value) {
+ // value is converted to Long ensuring equals works with the parsed json string.
+ return internalPut(key, new Long(value));
+ }
+
+ public Marker put(String key, String value) {
+ return internalPut(key, value);
+ }
+
+ private Marker internalPut(String key, Object value) {
+ assert (key != null) && (value != null);
+ assert !content.containsKey(key);
+ content.put(key, value);
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ // The JSONObject does not support a predictable sorted serialization of the object.
+ // Therefore, a TreeMap is used and iteration is over the keySet.
+ StringBuffer sb = new StringBuffer(kPrefix + tool);
+ boolean first = true;
+ sb.append('{');
+ for (String key : content.keySet()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(JSONObject.toString(key, content.get(key)));
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Marker) {
+ Marker other = (Marker) obj;
+ return (tool == other.tool) && content.equals(other.content);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return tool.hashCode() + 3 * content.hashCode();
+ }
+
+ // Try to parse str as a marker.
+ // Returns null if parsing fails.
+ public static Marker parse(String str) {
+ if (str.startsWith(kD8prefix)) {
+ return internalParse(Tool.D8, str.substring(kD8prefix.length() - 1));
+ }
+ if (str.startsWith(kR8prefix)) {
+ return internalParse(Tool.R8, str.substring(kR8prefix.length() - 1));
+ }
+ return null;
+ }
+
+ private static Marker internalParse(Tool tool, String str) {
+ try {
+ Object result = new JSONParser().parse(str);
+ if (result instanceof JSONObject) {
+ return new Marker(tool, (JSONObject) result);
+ }
+ } catch (ParseException e) {
+ // Fall through.
+ }
+ return null;
+ }
+}
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 3432b62..f4fa536 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -318,7 +318,12 @@
// 1. Place the remaining files based on their packages in sorted order.
// Start with 1 file. The package populator will add more if needed.
- nameToFileMap.put(0, new VirtualFile(0, writer.namingLens));
+ VirtualFile main = new VirtualFile(0, writer.namingLens);
+ nameToFileMap.put(0, main);
+ if (writer.markerString != null) {
+ main.transaction.addString(writer.markerString);
+ main.commitTransaction();
+ }
// First fill required classes into the main dex file.
fillForMainDexList(classes);
@@ -925,7 +930,7 @@
} else {
assert clazz.superType != null;
// We don't have a package, add this to a list of classes that we will add last.
- assert current.transaction.isEmpty();
+ assert current.transaction.classes.isEmpty();
nonPackageClasses.add(clazz);
continue;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 3feae5f..a107794 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.graph.DexDebugEvent.AdvanceLine;
import com.android.tools.r8.graph.DexDebugEvent.AdvancePC;
import com.android.tools.r8.graph.DexDebugEvent.Default;
@@ -287,6 +288,18 @@
return canonicalize(strings, new DexString(source));
}
+ // Debugging support to extract marking string.
+ synchronized public Marker extractMarker() {
+ // This is slow but it is not needed for any production code yet.
+ for (DexString dexString : strings.keySet()) {
+ Marker result = Marker.parse(dexString.toString());
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
public DexType createType(DexString descriptor) {
assert !sorted;
DexType type = new DexType(descriptor);
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 e6914ec..75a6d35 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -21,7 +21,7 @@
this.content = content;
}
- DexString(String string) {
+ public DexString(String string) {
this.size = string.length();
this.content = encode(string);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index 74a0800..c8157d6 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -90,8 +90,7 @@
for (IndexedDexItem item : items) {
item.assignVirtualFileIndex(virtualFileId, index);
// For strings collect the first jumbo string (if any).
- if (index > Constants.MAX_NON_JUMBO_INDEX) {
- assert item instanceof DexString;
+ if ((index > Constants.MAX_NON_JUMBO_INDEX) && (item instanceof DexString)) {
if (index == Constants.FIRST_JUMBO_INDEX) {
firstJumboString = (DexString) item;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index d43dc36..6f94b1e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -50,7 +50,7 @@
public class IRConverter {
- public static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
+ private static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
private final Timing timing;
public final DexApplication application;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index f547209..ce6ad76 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -212,15 +212,15 @@
public final DexEncodedMethod target;
public final Invoke invoke;
- public final Reason reason;
+ final Reason reason;
- public InlineAction(DexEncodedMethod target, Invoke invoke, Reason reason) {
+ InlineAction(DexEncodedMethod target, Invoke invoke, Reason reason) {
this.target = target;
this.invoke = invoke;
this.reason = reason;
}
- public boolean forceInline() {
+ boolean forceInline() {
return reason != Reason.SIMPLE;
}
@@ -313,16 +313,6 @@
return true;
}
- /// Computer the receiver value for the holder method.
- private Value receiverValue(DexEncodedMethod method, IRCode code) {
- // Ignore static methods.
- if (method.accessFlags.isStatic()) {
- return null;
- }
- // Find the outValue of the first argument instruction in the first block.
- return code.collectArguments().get(0);
- }
-
public void performInlining(DexEncodedMethod method, IRCode code, CallGraph callGraph) {
int instruction_allowance = 1500;
instruction_allowance -= numberOfInstructions(code);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index fb6c2eb..d32f7f4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -29,7 +29,7 @@
private final CallGraph callGraph;
private final InliningInfo info;
- public InliningOracle(
+ InliningOracle(
Inliner inliner,
DexEncodedMethod method,
CallGraph callGraph) {
@@ -39,7 +39,7 @@
info = Log.ENABLED ? new InliningInfo(method) : null;
}
- public void finish() {
+ void finish() {
if (Log.ENABLED) {
System.out.println(info.toString());
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index ca22e50..9fea848 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -45,6 +46,9 @@
// Silencing output.
public boolean quiet = false;
+ // Hidden marker for classes.dex
+ public Marker customizedMarker;
+
public List<String> methodsFilter = ImmutableList.of();
public int minApiLevel = Constants.DEFAULT_ANDROID_API;
// Skipping min_api check and compiling an intermediate result intended for later merging.
diff --git a/src/test/java/com/android/tools/r8/d8/D8FrameworkTest.java b/src/test/java/com/android/tools/r8/d8/D8FrameworkTest.java
new file mode 100644
index 0000000..2878ed0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/d8/D8FrameworkTest.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2017, the Rex 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.d8;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationException;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Simple test that compiles framework.jar with D8 a number of times with
+ * various number of threads available to the compiler.
+ * This test also tests the hidden marker inserted into classes.dex.
+ */
+@RunWith( Parameterized.class )
+public class D8FrameworkTest {
+
+ private static final Path FRAMEWORK_JAR =
+ Paths.get("tools/linux/art-5.1.1/product/mako/system/framework/framework.jar");
+
+ @Rule
+ public TemporaryFolder output = ToolHelper.getTemporaryFolderForTest();
+
+ @Parameters(name = "Number of threads = {0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { {1}, {2}, {4}, {8}, {16} });
+ }
+
+ private final int threads;
+
+ public D8FrameworkTest(int threads) {
+ this.threads = threads;
+ }
+
+ @Test
+ public void compile() throws CompilationException, IOException, ExecutionException {
+ D8Command command = D8Command.builder()
+ .setMinApiLevel(Constants.ANDROID_N_API)
+ .addProgramFiles(FRAMEWORK_JAR)
+ .build();
+ Marker marker = new Marker(Tool.D8)
+ .put("revision", "1.0.0")
+ .put("threads", threads);
+ Marker selfie = Marker.parse(marker.toString());
+ assert marker.equals(selfie);
+ AndroidApp app = ToolHelper.runD8(command, options -> {
+ options.customizedMarker = marker;
+ options.numberOfThreads = threads;
+ });
+ DexApplication dexApp =
+ new ApplicationReader(app, new InternalOptions(), new Timing("D8FrameworkTest")).read();
+ Marker readMarker = dexApp.dexItemFactory.extractMarker();
+ assertEquals(marker, readMarker);
+ }
+}
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 a113003..a87985e 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -581,7 +581,7 @@
DexApplication application = builder.build();
AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
ApplicationWriter writer = new ApplicationWriter(
- application, appInfo, options, null, NamingLens.getIdentityLens(), null);
+ application, appInfo, options, null, null, NamingLens.getIdentityLens(), null);
ExecutorService executor = ThreadUtils.getExecutorService(options);
try {
return writer.write(null, executor);