blob: 6d5e88032622a306a714909540678d09a068a0a8 [file] [log] [blame]
// Copyright (c) 2022, 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.dump;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.dex.Marker.Backend;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.features.FeatureSplitConfiguration;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.profile.art.ArtProfileProvider;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class DumpOptions {
// The following keys and values should not be changed to keep the dump utility backward
// compatible with previous versions. They are also used by the python script compileDump and
// the corresponding CompileDumpCompatR8 java class.
private static final String BACKEND_KEY = "backend";
private static final String TOOL_KEY = "tool";
private static final String MODE_KEY = "mode";
private static final String DEBUG_MODE_VALUE = "debug";
private static final String RELEASE_MODE_VALUE = "release";
private static final String MIN_API_KEY = "min-api";
private static final String OPTIMIZE_MULTIDEX_FOR_LINEAR_ALLOC_KEY =
"optimize-multidex-for-linear-alloc";
private static final String THREAD_COUNT_KEY = "thread-count";
private static final String DESUGAR_STATE_KEY = "desugar-state";
private static final String INTERMEDIATE_KEY = "intermediate";
private static final String INCLUDE_DATA_RESOURCES_KEY = "include-data-resources";
private static final String TREE_SHAKING_KEY = "tree-shaking";
private static final String MINIFICATION_KEY = "minification";
private static final String FORCE_PROGUARD_COMPATIBILITY_KEY = "force-proguard-compatibility";
public static final String SYSTEM_PROPERTY_PREFIX = "system-property-";
private static final String ENABLE_MISSING_LIBRARY_API_MODELING =
"enable-missing-library-api-modeling";
private static final String ANDROID_PLATFORM_BUILD = "android-platform-build";
private static final String TRACE_REFERENCES_CONSUMER = "trace_references_consumer";
private final Backend backend;
private final Tool tool;
private final CompilationMode compilationMode;
private final int minApi;
private final boolean optimizeMultidexForLinearAlloc;
private final int threadCount;
private final DesugarState desugarState;
private final Optional<Boolean> intermediate;
private final Optional<Boolean> includeDataResources;
private final Optional<Boolean> treeShaking;
private final Optional<Boolean> minification;
private final Optional<Boolean> forceProguardCompatibility;
// Dump if present.
private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final FeatureSplitConfiguration featureSplitConfiguration;
private final ProguardConfiguration proguardConfiguration;
private final List<ProguardConfigurationRule> mainDexKeepRules;
private final Collection<ArtProfileProvider> artProfileProviders;
private final Collection<StartupProfileProvider> startupProfileProviders;
private final boolean enableMissingLibraryApiModeling;
private final boolean isAndroidPlatformBuild;
private final Map<String, String> systemProperties;
// TraceReferences only.
private final String traceReferencesConsumer;
// Reporting only.
private final boolean dumpInputToFile;
private DumpOptions(
Backend backend,
Tool tool,
CompilationMode compilationMode,
int minAPI,
DesugaredLibrarySpecification desugaredLibrarySpecification,
boolean optimizeMultidexForLinearAlloc,
int threadCount,
DesugarState desugarState,
Optional<Boolean> intermediate,
Optional<Boolean> includeDataResources,
Optional<Boolean> treeShaking,
Optional<Boolean> minification,
Optional<Boolean> forceProguardCompatibility,
FeatureSplitConfiguration featureSplitConfiguration,
ProguardConfiguration proguardConfiguration,
List<ProguardConfigurationRule> mainDexKeepRules,
Collection<ArtProfileProvider> artProfileProviders,
Collection<StartupProfileProvider> startupProfileProviders,
boolean enableMissingLibraryApiModeling,
boolean isAndroidPlatformBuild,
Map<String, String> systemProperties,
boolean dumpInputToFile,
String traceReferencesConsumer) {
this.backend = backend;
this.tool = tool;
this.compilationMode = compilationMode;
this.minApi = minAPI;
this.desugaredLibrarySpecification = desugaredLibrarySpecification;
this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc;
this.threadCount = threadCount;
this.desugarState = desugarState;
this.intermediate = intermediate;
this.includeDataResources = includeDataResources;
this.treeShaking = treeShaking;
this.minification = minification;
this.forceProguardCompatibility = forceProguardCompatibility;
this.featureSplitConfiguration = featureSplitConfiguration;
this.proguardConfiguration = proguardConfiguration;
this.mainDexKeepRules = mainDexKeepRules;
this.artProfileProviders = artProfileProviders;
this.startupProfileProviders = startupProfileProviders;
this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
this.isAndroidPlatformBuild = isAndroidPlatformBuild;
this.systemProperties = systemProperties;
this.dumpInputToFile = dumpInputToFile;
this.traceReferencesConsumer = traceReferencesConsumer;
}
public String getBuildPropertiesFileContent() {
StringBuilder builder = new StringBuilder();
getBuildProperties()
.forEach((key, value) -> builder.append(key).append("=").append(value).append("\n"));
return builder.toString();
}
public Map<String, String> getBuildProperties() {
Map<String, String> buildProperties = new LinkedHashMap<>();
addDumpEntry(buildProperties, TOOL_KEY, tool.name());
if (threadCount != ThreadUtils.NOT_SPECIFIED) {
addDumpEntry(buildProperties, THREAD_COUNT_KEY, threadCount);
}
if (tool != Tool.TraceReferences) {
// We keep the following values for backward compatibility.
addDumpEntry(buildProperties, BACKEND_KEY, backend.name());
addDumpEntry(
buildProperties,
MODE_KEY,
compilationMode == CompilationMode.DEBUG ? DEBUG_MODE_VALUE : RELEASE_MODE_VALUE);
addDumpEntry(buildProperties, MIN_API_KEY, minApi);
addDumpEntry(
buildProperties, OPTIMIZE_MULTIDEX_FOR_LINEAR_ALLOC_KEY, optimizeMultidexForLinearAlloc);
addDumpEntry(buildProperties, DESUGAR_STATE_KEY, desugarState);
addDumpEntry(
buildProperties, ENABLE_MISSING_LIBRARY_API_MODELING, enableMissingLibraryApiModeling);
if (isAndroidPlatformBuild) {
addDumpEntry(buildProperties, ANDROID_PLATFORM_BUILD, isAndroidPlatformBuild);
}
addOptionalDumpEntry(buildProperties, INTERMEDIATE_KEY, intermediate);
addOptionalDumpEntry(buildProperties, INCLUDE_DATA_RESOURCES_KEY, includeDataResources);
addOptionalDumpEntry(buildProperties, TREE_SHAKING_KEY, treeShaking);
addOptionalDumpEntry(
buildProperties, FORCE_PROGUARD_COMPATIBILITY_KEY, forceProguardCompatibility);
} else {
addDumpEntry(buildProperties, TRACE_REFERENCES_CONSUMER, traceReferencesConsumer);
}
addOptionalDumpEntry(buildProperties, MINIFICATION_KEY, minification);
ArrayList<String> sortedKeys = new ArrayList<>(systemProperties.keySet());
sortedKeys.sort(String::compareTo);
sortedKeys.forEach(
key ->
addDumpEntry(buildProperties, SYSTEM_PROPERTY_PREFIX + key, systemProperties.get(key)));
return buildProperties;
}
public static void parse(String content, DumpOptions.Builder builder) {
StringUtils.splitForEach(
content,
'\n',
line -> {
String trimmed = line.trim();
int i = trimmed.indexOf('=');
if (i < 0) {
throw new RuntimeException("Invalid dump line. Expected = in line: '" + trimmed + "'");
}
String key = trimmed.substring(0, i).trim();
String value = trimmed.substring(i + 1).trim();
parseKeyValue(builder, key, value);
});
}
private static void parseKeyValue(Builder builder, String key, String value) {
switch (key) {
case BACKEND_KEY:
builder.setBackend(Backend.valueOf(value));
return;
case TOOL_KEY:
builder.setTool(Tool.valueOf(value));
return;
case MODE_KEY:
if (value.equals(DEBUG_MODE_VALUE)) {
builder.setCompilationMode(CompilationMode.DEBUG);
} else if (value.equals(RELEASE_MODE_VALUE)) {
builder.setCompilationMode(CompilationMode.RELEASE);
} else {
parseKeyValueError(key, value);
}
return;
case MIN_API_KEY:
builder.setMinApi(Integer.parseInt(value));
return;
case OPTIMIZE_MULTIDEX_FOR_LINEAR_ALLOC_KEY:
builder.setOptimizeMultidexForLinearAlloc(Boolean.parseBoolean(value));
return;
case THREAD_COUNT_KEY:
builder.setThreadCount(Integer.parseInt(value));
return;
case DESUGAR_STATE_KEY:
builder.setDesugarState(DesugarState.valueOf(value));
return;
case INTERMEDIATE_KEY:
builder.setIntermediate(Boolean.parseBoolean(value));
return;
case INCLUDE_DATA_RESOURCES_KEY:
builder.setIncludeDataResources(Optional.of(Boolean.parseBoolean(value)));
return;
case TREE_SHAKING_KEY:
builder.setTreeShaking(Boolean.parseBoolean(value));
return;
case MINIFICATION_KEY:
builder.setMinification(Boolean.parseBoolean(value));
return;
case FORCE_PROGUARD_COMPATIBILITY_KEY:
builder.setForceProguardCompatibility(Boolean.parseBoolean(value));
return;
case TRACE_REFERENCES_CONSUMER:
builder.setTraceReferencesConsumer(value);
return;
default:
if (key.startsWith(SYSTEM_PROPERTY_PREFIX)) {
builder.setSystemProperty(key.substring(SYSTEM_PROPERTY_PREFIX.length()), value);
} else {
parseKeyValueError(key, value);
}
}
}
private static void parseKeyValueError(String key, String value) {
throw new RuntimeException("Unknown key value pair: " + key + " = " + value);
}
public Tool getTool() {
return tool;
}
public CompilationMode getCompilationMode() {
return compilationMode;
}
public int getMinApi() {
return minApi;
}
private void addOptionalDumpEntry(
Map<String, String> buildProperties, String key, Optional<?> optionalValue) {
optionalValue.ifPresent(bool -> addDumpEntry(buildProperties, key, bool));
}
private void addDumpEntry(Map<String, String> buildProperties, String key, Object value) {
buildProperties.put(key, Objects.toString(value));
}
private boolean hasDesugaredLibraryConfiguration() {
return desugaredLibrarySpecification != null && !desugaredLibrarySpecification.isEmpty();
}
public String getDesugaredLibraryJsonSource() {
if (hasDesugaredLibraryConfiguration()) {
return desugaredLibrarySpecification.getJsonSource();
}
return null;
}
public FeatureSplitConfiguration getFeatureSplitConfiguration() {
return featureSplitConfiguration;
}
public String getParsedProguardConfiguration() {
return proguardConfiguration == null ? null : proguardConfiguration.getParsedConfiguration();
}
public boolean hasMainDexKeepRules() {
return mainDexKeepRules != null && !mainDexKeepRules.isEmpty();
}
public List<ProguardConfigurationRule> getMainDexKeepRules() {
return mainDexKeepRules;
}
public boolean hasArtProfileProviders() {
return artProfileProviders != null && !artProfileProviders.isEmpty();
}
public Collection<ArtProfileProvider> getArtProfileProviders() {
return artProfileProviders;
}
public boolean hasStartupProfileProviders() {
return startupProfileProviders != null && !startupProfileProviders.isEmpty();
}
public Collection<StartupProfileProvider> getStartupProfileProviders() {
return startupProfileProviders;
}
public boolean dumpInputToFile() {
return dumpInputToFile;
}
public static Builder builder(Tool tool) {
return new Builder().setTool(tool);
}
public static class Builder {
// Initialize backend to DEX for backwards compatibility.
private Backend backend = Backend.DEX;
private Tool tool;
private CompilationMode compilationMode;
private int minApi;
private boolean optimizeMultidexForLinearAlloc;
private int threadCount;
private DesugarState desugarState;
private Optional<Boolean> intermediate = Optional.empty();
private Optional<Boolean> includeDataResources = Optional.empty();
private Optional<Boolean> treeShaking = Optional.empty();
private Optional<Boolean> minification = Optional.empty();
private Optional<Boolean> forceProguardCompatibility = Optional.empty();
// Dump if present.
private DesugaredLibrarySpecification desugaredLibrarySpecification;
private FeatureSplitConfiguration featureSplitConfiguration;
private ProguardConfiguration proguardConfiguration;
private List<ProguardConfigurationRule> mainDexKeepRules;
private Collection<ArtProfileProvider> artProfileProviders;
private Collection<StartupProfileProvider> startupProfileProviders;
private boolean enableMissingLibraryApiModeling = false;
private boolean isAndroidPlatformBuild = false;
private String traceReferencesConsumer = null;
private Map<String, String> systemProperties = new HashMap<>();
// Reporting only.
private boolean dumpInputToFile;
public Builder() {}
public Builder setBackend(Backend backend) {
this.backend = backend;
return this;
}
public Builder setTool(Tool tool) {
this.tool = tool;
return this;
}
public Builder setTraceReferencesConsumer(String traceReferencesConsumer) {
this.traceReferencesConsumer = traceReferencesConsumer;
return this;
}
public Builder setCompilationMode(CompilationMode compilationMode) {
this.compilationMode = compilationMode;
return this;
}
public Builder setMinApi(int minAPI) {
this.minApi = minAPI;
return this;
}
public Builder setDesugaredLibraryConfiguration(
DesugaredLibrarySpecification desugaredLibrarySpecification) {
this.desugaredLibrarySpecification = desugaredLibrarySpecification;
return this;
}
public Builder setOptimizeMultidexForLinearAlloc(boolean optimizeMultidexForLinearAlloc) {
this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc;
return this;
}
public Builder setThreadCount(int threadCount) {
this.threadCount = threadCount;
return this;
}
public Builder setDesugarState(DesugarState desugarState) {
this.desugarState = desugarState;
return this;
}
public Builder setIntermediate(boolean intermediate) {
this.intermediate = Optional.of(intermediate);
return this;
}
public Builder setIncludeDataResources(Optional<Boolean> includeDataResources) {
this.includeDataResources = includeDataResources;
return this;
}
public Builder setForceProguardCompatibility(boolean forceProguardCompatibility) {
this.forceProguardCompatibility = Optional.of(forceProguardCompatibility);
return this;
}
public Builder setMinification(boolean minification) {
this.minification = Optional.of(minification);
return this;
}
public Builder setTreeShaking(boolean treeShaking) {
this.treeShaking = Optional.of(treeShaking);
return this;
}
public Builder setDumpInputToFile(boolean dumpInputToFile) {
this.dumpInputToFile = dumpInputToFile;
return this;
}
public Builder setFeatureSplitConfiguration(
FeatureSplitConfiguration featureSplitConfiguration) {
this.featureSplitConfiguration = featureSplitConfiguration;
return this;
}
public Builder setProguardConfiguration(ProguardConfiguration proguardConfiguration) {
this.proguardConfiguration = proguardConfiguration;
return this;
}
public Builder setMainDexKeepRules(List<ProguardConfigurationRule> mainDexKeepRules) {
this.mainDexKeepRules = mainDexKeepRules;
return this;
}
public Builder setArtProfileProviders(Collection<ArtProfileProvider> artProfileProviders) {
this.artProfileProviders = artProfileProviders;
return this;
}
public Builder setStartupProfileProviders(
Collection<StartupProfileProvider> startupProfileProviders) {
this.startupProfileProviders = startupProfileProviders;
return this;
}
public Builder setEnableMissingLibraryApiModeling(boolean value) {
enableMissingLibraryApiModeling = value;
return this;
}
public Builder setAndroidPlatformBuild(boolean value) {
isAndroidPlatformBuild = value;
return this;
}
public Builder setSystemProperty(String key, String value) {
this.systemProperties.put(key, value);
return this;
}
public Builder readCurrentSystemProperties() {
getCurrentSystemProperties().forEach(this::setSystemProperty);
return this;
}
public static Map<String, String> getCurrentSystemProperties() {
Map<String, String> systemProperties = new TreeMap<>();
System.getProperties()
.stringPropertyNames()
.forEach(
name -> {
if (name.startsWith("com.android.tools.r8.")) {
String value = System.getProperty(name);
systemProperties.put(name, value);
}
});
return systemProperties;
}
public DumpOptions build() {
assert tool != null;
assert tool == Tool.TraceReferences || backend != null;
return new DumpOptions(
backend,
tool,
compilationMode,
minApi,
desugaredLibrarySpecification,
optimizeMultidexForLinearAlloc,
threadCount,
desugarState,
intermediate,
includeDataResources,
treeShaking,
minification,
forceProguardCompatibility,
featureSplitConfiguration,
proguardConfiguration,
mainDexKeepRules,
artProfileProviders,
startupProfileProviders,
enableMissingLibraryApiModeling,
isAndroidPlatformBuild,
systemProperties,
dumpInputToFile,
traceReferencesConsumer);
}
}
}