Support machine specifications as input
Change-Id: I77bafc9e72ee3e35b5a8c62d48ce23e71604e020
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
index 83ee3ec..bc61d60 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
@@ -8,7 +8,9 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecificationParser;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.synthesis.SyntheticNaming;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -20,6 +22,7 @@
public static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
private static final int MIN_HUMAN_CONFIGURATION_FORMAT_VERSION = 100;
+ private static final int MIN_MACHINE_CONFIGURATION_FORMAT_VERSION = 200;
public static DesugaredLibrarySpecification parseDesugaredLibrarySpecification(
StringResource stringResource,
@@ -27,26 +30,8 @@
Reporter reporter,
boolean libraryCompilation,
int minAPILevel) {
- Origin origin = stringResource.getOrigin();
- assert origin != null;
- String jsonConfigString;
- JsonObject jsonConfig;
- try {
- jsonConfigString = stringResource.getString();
- JsonParser parser = new JsonParser();
- jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
- } catch (Exception e) {
- throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
- }
-
- if (isHumanSpecification(jsonConfig, reporter, origin)) {
- return new HumanDesugaredLibrarySpecificationParser(
- dexItemFactory, reporter, libraryCompilation, minAPILevel)
- .parse(origin, jsonConfigString, jsonConfig);
- }
- return new LegacyDesugaredLibrarySpecificationParser(
- dexItemFactory, reporter, libraryCompilation, minAPILevel)
- .parse(origin, jsonConfigString, jsonConfig);
+ return parseDesugaredLibrarySpecificationforTesting(
+ stringResource, dexItemFactory, reporter, libraryCompilation, minAPILevel, flags -> {});
}
public static DesugaredLibrarySpecification parseDesugaredLibrarySpecificationforTesting(
@@ -67,18 +52,53 @@
} catch (Exception e) {
throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
}
+ // Machine Specification is the shippable format released in Maven. D8/R8 has to be *very*
+ // backward compatible to any machine specification, and raise proper error messages for
+ // compatibility issues. The format is also exhaustive (Very limited pattern matching, if any).
+ // It can hardly be written by hand and is always generated.
+ if (isMachineSpecification(jsonConfig, reporter, origin)) {
+ return new MachineDesugaredLibrarySpecificationParser(
+ dexItemFactory, reporter, libraryCompilation, minAPILevel, new SyntheticNaming())
+ .parse(origin, jsonConfigString, jsonConfig);
+ }
+ // Human Specification is the easy to write format for developers and allows one to widely use
+ // pattern matching. This format is mainly used for development and to generate the machine
+ // specification. D8/R8 is *not* backward compatible with any previous version of human
+ // specification, which is therefore not suited to be shipped for external users. It can be
+ // shipped to internal users where we can easily update the D8/R8 compiler and the
+ // desugared library specification at the same time.
if (isHumanSpecification(jsonConfig, reporter, origin)) {
return new HumanDesugaredLibrarySpecificationParser(
dexItemFactory, reporter, libraryCompilation, minAPILevel)
.parse(origin, jsonConfigString, jsonConfig, topLevelFlagsAmender);
}
+ // Legacy specification is the legacy format, as was shipped desugared library JDK8.
+ // Hopefully the day will come where this format is no longer supported, and the other formats
+ // shall always be preferred+.
return new LegacyDesugaredLibrarySpecificationParser(
dexItemFactory, reporter, libraryCompilation, minAPILevel)
.parse(origin, jsonConfigString, jsonConfig, topLevelFlagsAmender);
}
+ public static boolean isMachineSpecification(
+ JsonObject jsonConfig, Reporter reporter, Origin origin) {
+ ensureConfigurationFormatVersion(jsonConfig, reporter, origin);
+
+ int formatVersion = jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt();
+ return formatVersion >= MIN_MACHINE_CONFIGURATION_FORMAT_VERSION;
+ }
+
public static boolean isHumanSpecification(
JsonObject jsonConfig, Reporter reporter, Origin origin) {
+ ensureConfigurationFormatVersion(jsonConfig, reporter, origin);
+
+ int formatVersion = jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt();
+ return formatVersion >= MIN_HUMAN_CONFIGURATION_FORMAT_VERSION
+ && formatVersion < MIN_MACHINE_CONFIGURATION_FORMAT_VERSION;
+ }
+
+ private static void ensureConfigurationFormatVersion(
+ JsonObject jsonConfig, Reporter reporter, Origin origin) {
if (!jsonConfig.has(CONFIGURATION_FORMAT_VERSION_KEY)) {
throw reporter.fatalError(
new StringDiagnostic(
@@ -87,8 +107,5 @@
+ "'",
origin));
}
-
- return jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt()
- >= MIN_HUMAN_CONFIGURATION_FORMAT_VERSION;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 0d9ef85..f4a6d2a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -56,10 +56,12 @@
this.rewritingFlags = rewritingFlags;
}
+ @Override
public boolean isEmpty() {
return rewritingFlags.isEmpty();
}
+ @Override
public boolean isLibraryCompilation() {
return libraryCompilation;
}
@@ -72,10 +74,12 @@
return rewritingFlags;
}
- public AndroidApiLevel getRequiredCompilationAPILevel() {
- return topLevelFlags.getRequiredCompilationAPILevel();
+ @Override
+ public AndroidApiLevel getRequiredCompilationApiLevel() {
+ return topLevelFlags.getRequiredCompilationApiLevel();
}
+ @Override
public String getSynthesizedLibraryClassesPackagePrefix() {
return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
}
@@ -84,6 +88,7 @@
return topLevelFlags.getIdentifier();
}
+ @Override
public String getJsonSource() {
return topLevelFlags.getJsonSource();
}
@@ -92,6 +97,7 @@
return topLevelFlags.supportAllCallbacksFromLibrary();
}
+ @Override
public List<String> getExtraKeepRules() {
return topLevelFlags.getExtraKeepRules();
}
@@ -216,10 +222,6 @@
return false;
}
- public AndroidApiLevel getRequiredCompilationApiLevel() {
- return topLevelFlags.getRequiredCompilationAPILevel();
- }
-
@Override
public MachineDesugaredLibrarySpecification toMachineSpecification(
DexApplication app, Timing timing) throws IOException {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
index 6cdd123..031ca29 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.AMEND_LIBRARY_FIELD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.AMEND_LIBRARY_METHOD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.API_GENERIC_TYPES_CONVERSION_KEY;
@@ -62,6 +63,9 @@
public class MachineDesugaredLibrarySpecificationParser {
+ private static final int MIN_SUPPORTED_VERSION = 200;
+ private static final int MAX_SUPPORTED_VERSION = 200;
+
private static final String ERROR_MESSAGE_PREFIX = "Invalid desugared library specification: ";
private final DexItemFactory dexItemFactory;
@@ -127,6 +131,19 @@
Origin origin, String jsonConfigString, JsonObject jsonConfig) {
this.origin = origin;
this.jsonConfig = jsonConfig;
+ int machineVersion = required(jsonConfig, CONFIGURATION_FORMAT_VERSION_KEY).getAsInt();
+ if (machineVersion < MIN_SUPPORTED_VERSION || machineVersion > MAX_SUPPORTED_VERSION) {
+ throw reporter.fatalError(
+ new StringDiagnostic(
+ "Unsupported machine version number "
+ + machineVersion
+ + " not in ["
+ + MIN_SUPPORTED_VERSION
+ + ","
+ + MAX_SUPPORTED_VERSION
+ + "]",
+ origin));
+ }
MachineTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString);
parsePackageMap();
MachineRewritingFlags rewritingFlags = parseRewritingFlags();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
index 389705b..c5c1b4b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
@@ -44,7 +44,7 @@
this.extraKeepRules = extraKeepRules;
}
- public AndroidApiLevel getRequiredCompilationAPILevel() {
+ public AndroidApiLevel getRequiredCompilationApiLevel() {
return requiredCompilationAPILevel;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
index e55127c..f5d81fa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.AMEND_LIBRARY_FIELD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.AMEND_LIBRARY_METHOD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.API_GENERIC_TYPES_CONVERSION_KEY;
@@ -55,6 +56,8 @@
public class MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter {
+ private static final int MACHINE_VERSION_NUMBER = 200;
+
private final DexItemFactory factory;
private final Map<String, String> packageMap = new TreeMap<>();
private static final String chars =
@@ -78,7 +81,7 @@
HashMap<String, Object> toJson = new LinkedHashMap<>();
exportTopLevelFlags(machineSpec.getTopLevelFlags(), toJson);
- // TODO(): export format version for compat internal to R8.
+ toJson.put(CONFIGURATION_FORMAT_VERSION_KEY, MACHINE_VERSION_NUMBER);
toJson.put(COMMON_FLAGS_KEY, rewritingFlagsToString(machineSpec.getCommonFlags()));
toJson.put(PROGRAM_FLAGS_KEY, rewritingFlagsToString(machineSpec.getProgramFlags()));
@@ -95,7 +98,7 @@
toJson.put(IDENTIFIER_KEY, topLevelFlags.getIdentifier());
toJson.put(
REQUIRED_COMPILATION_API_LEVEL_KEY,
- topLevelFlags.getRequiredCompilationAPILevel().getLevel());
+ topLevelFlags.getRequiredCompilationApiLevel().getLevel());
toJson.put(
SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY,
topLevelFlags.getSynthesizedLibraryClassesPackagePrefix());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index ec8c5f7..cd5c568 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -253,8 +253,8 @@
assertEquals(kr1, kr2);
assertEquals(topLevelFlags1.getIdentifier(), topLevelFlags2.getIdentifier());
assertEquals(
- topLevelFlags1.getRequiredCompilationAPILevel().getLevel(),
- topLevelFlags2.getRequiredCompilationAPILevel().getLevel());
+ topLevelFlags1.getRequiredCompilationApiLevel().getLevel(),
+ topLevelFlags2.getRequiredCompilationApiLevel().getLevel());
assertEquals(
topLevelFlags1.getSynthesizedLibraryClassesPackagePrefix(),
topLevelFlags2.getSynthesizedLibraryClassesPackagePrefix());