blob: 2509e124a4366538e47eb20d4d376c367cae431a [file] [log] [blame]
// 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;
import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
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.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
public class DexFileMergerHelper {
private final Map<String, Integer> inputOrdering;
private DexFileMergerHelper(Map<String, Integer> inputOrdering) {
this.inputOrdering = inputOrdering;
}
private DexProgramClass keepFirstProgramClassConflictResolver(
DexProgramClass a, DexProgramClass b) {
String aPath = a.getOrigin().parent().part();
String bPath = b.getOrigin().parent().part();
Integer aIndex = inputOrdering.get(aPath);
Integer bIndex = inputOrdering.get(bPath);
if (aIndex == null || bIndex == null) {
StringBuilder builder = new StringBuilder();
builder.append("Class parent paths not found among input paths: ");
if (aIndex == null) {
builder.append(aPath);
}
if (bIndex == null) {
if (aIndex == null) {
builder.append(", ");
}
builder.append(bPath);
}
throw new RuntimeException(builder.toString());
}
return aIndex <= bIndex ? a.get() : b.get();
}
public static void run(
D8Command command, Boolean minimalMainDex, Map<String, Integer> inputOrdering)
throws CompilationFailedException {
InternalOptions options = command.getInternalOptions();
ExceptionUtils.withD8CompilationHandler(
options.reporter,
() -> runInternal(command.getInputApp(), options, minimalMainDex, inputOrdering));
}
private static void runInternal(
AndroidApp inputApp,
InternalOptions options,
Boolean minimalMainDex,
Map<String, Integer> inputOrdering)
throws IOException {
options.desugarState = DesugarState.OFF;
options.enableMainDexListCheck = false;
options.minimalMainDex = minimalMainDex;
assert !options.isMinifying();
options.enableInlining = false;
options.outline.enabled = false;
ExecutorService executor = ThreadUtils.getExecutorService(ThreadUtils.NOT_SPECIFIED);
try {
try {
Timing timing = new Timing("DexFileMerger");
DexApplication app =
new ApplicationReader(inputApp, options, timing)
.read(
null,
executor,
new DexFileMergerHelper(inputOrdering)::keepFirstProgramClassConflictResolver);
AppInfo appInfo = new AppInfo(app);
app = D8.optimize(app, appInfo, options, timing, executor);
List<Marker> markers = app.dexItemFactory.extractMarkers();
assert !options.hasMethodsFilter();
ApplicationWriter writer =
new ApplicationWriter(
app,
null,
options,
markers,
GraphLense.getIdentityLense(),
NamingLens.getIdentityLens(),
null);
writer.write(executor);
options.printWarnings();
} catch (ExecutionException e) {
throw unwrapExecutionException(e);
} finally {
options.signalFinishedToConsumers();
}
} finally {
executor.shutdown();
}
}
public static void runD8ForTesting(D8Command command, boolean dontCreateMarkerInD8)
throws CompilationFailedException {
InternalOptions options = command.getInternalOptions();
options.testing.dontCreateMarkerInD8 = dontCreateMarkerInD8;
D8.runForTesting(command.getInputApp(), options);
}
}