Introduce retarget_static_field
Support for LocalDateTime#EPOCH now possible
Bug: 222647019
Change-Id: I5eb6f81c2e3065120011b16fc71066c11b7e7f9b
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 29dc73f..ce94d5d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -93,6 +93,12 @@
return opcode == Opcodes.GETSTATIC;
}
+ public boolean isStaticFieldPut() {
+ return opcode == Opcodes.PUTSTATIC;
+ }
+
+ public abstract CfFieldInstruction createWithField(DexField field);
+
@Override
public CfFieldInstruction asFieldInstruction() {
return this;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index 145bc94..2684c0d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -22,6 +22,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfInstanceFieldRead(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldReadInstruction(this);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index 6d01f49..c9138bb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -21,6 +21,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfInstanceFieldWrite(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldWrite(getField());
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
index 66fc48e..30715e1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -22,6 +22,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfStaticFieldRead(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldReadInstruction(this);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index 2cd0f26..24b5e6d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -21,6 +21,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfStaticFieldWrite(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldWrite(getField());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
index c943028..92bd91e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
@@ -8,8 +8,13 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.utils.Reporter;
import java.util.Map;
@@ -28,20 +33,23 @@
public static void run(AppView<?> appView) {
run(
appView.options().machineDesugaredLibrarySpecification.getAmendLibraryMethods(),
+ appView.options().machineDesugaredLibrarySpecification.getAmendLibraryFields(),
appView,
appView.options().reporter,
appView.computedMinApiLevel());
}
public static void run(
- Map<DexMethod, MethodAccessFlags> amendLibrary,
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField,
DexDefinitionSupplier definitions,
Reporter reporter,
ComputedApiLevel minAPILevel) {
- if (amendLibrary.isEmpty()) {
+ if (amendLibraryMethod.isEmpty() && amendLibraryField.isEmpty()) {
return;
}
- new DesugaredLibraryAmender(definitions, reporter, minAPILevel).run(amendLibrary);
+ new DesugaredLibraryAmender(definitions, reporter, minAPILevel)
+ .run(amendLibraryMethod, amendLibraryField);
}
private DesugaredLibraryAmender(
@@ -51,22 +59,40 @@
this.minAPILevel = minAPILevel;
}
- private void run(Map<DexMethod, MethodAccessFlags> amendLibrary) {
- amendLibrary.forEach(this::amendLibraryMethod);
+ private void run(
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField) {
+ amendLibraryMethod.forEach(this::amendLibraryMethod);
+ amendLibraryField.forEach(this::amendLibraryField);
+ }
+
+ private void amendLibraryField(DexField field, FieldAccessFlags fieldAccessFlags) {
+ DexLibraryClass libClass = getLibraryClass(field);
+ if (libClass == null) {
+ return;
+ }
+ if (libClass.lookupField(field) != null) {
+ return;
+ }
+ DexEncodedField encodedField =
+ DexEncodedField.syntheticBuilder()
+ .setField(field)
+ .setAccessFlags(fieldAccessFlags)
+ .setApiLevel(minAPILevel)
+ .build();
+ if (fieldAccessFlags.isStatic()) {
+ libClass.appendStaticField(encodedField);
+ } else {
+ libClass.appendInstanceField(encodedField);
+ }
}
private void amendLibraryMethod(DexMethod method, MethodAccessFlags methodAccessFlags) {
- DexClass dexClass = definitions.contextIndependentDefinitionFor(method.getHolderType());
- if (dexClass == null || !dexClass.isLibraryClass()) {
- // Consider just throwing an error.
- reporter.warning(
- "Desugared library: Cannot amend library method "
- + method
- + " because the holder is not a library class"
- + (dexClass == null ? "(null)." : "."));
+ DexLibraryClass libClass = getLibraryClass(method);
+ if (libClass == null) {
return;
}
- if (dexClass.lookupMethod(method) != null) {
+ if (libClass.lookupMethod(method) != null) {
return;
}
DexEncodedMethod encodedMethod =
@@ -76,6 +102,20 @@
.setCode(null)
.setApiLevelForDefinition(minAPILevel)
.build();
- dexClass.getMethodCollection().addMethod(encodedMethod);
+ libClass.getMethodCollection().addMethod(encodedMethod);
+ }
+
+ private DexLibraryClass getLibraryClass(DexReference reference) {
+ DexClass dexClass = definitions.contextIndependentDefinitionFor(reference.getContextType());
+ if (dexClass == null || !dexClass.isLibraryClass()) {
+ // Consider just throwing an error.
+ reporter.warning(
+ "Desugared library: Cannot amend library reference "
+ + reference
+ + " because the holder is not a library class"
+ + (dexClass == null ? "(null)." : "."));
+ return null;
+ }
+ return dexClass.asLibraryClass();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java
deleted file mode 100644
index d63efb6..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.ir.desugar.desugaredlibrary.humanspecification;
-
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.google.common.collect.ImmutableMap;
-import java.util.Map;
-
-/** Parse methods of the form: modifiers* returnType holder#name(arg0, ..., argN) */
-public abstract class AbstractMethodParser {
-
- private static final String SEPARATORS = "\\s+|,\\s+|#|\\(|\\)";
-
- private static final Map<String, Integer> modifiers =
- ImmutableMap.<String, Integer>builder()
- .put("public", Constants.ACC_PUBLIC)
- .put("private", Constants.ACC_PRIVATE)
- .put("protected", Constants.ACC_PROTECTED)
- .put("final", Constants.ACC_FINAL)
- .put("abstract", Constants.ACC_ABSTRACT)
- .put("static", Constants.ACC_STATIC)
- .build();
-
- final DexItemFactory factory;
-
- protected AbstractMethodParser(DexItemFactory factory) {
- this.factory = factory;
- }
-
- // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
- // method instead, then add a TraversalContinuation.
- public void parseMethod(String signature) {
- String[] tokens = signature.split(SEPARATORS);
- if (tokens.length < 3) {
- throw new CompilationError("Desugared library: cannot parse method " + signature);
- }
- methodStart();
- int first = parseModifiers(tokens);
- returnType(stringTypeToDexType(tokens[first]));
- holderType(stringTypeToDexType(tokens[first + 1]));
- methodName(factory.createString(tokens[first + 1 + 1]));
- for (int i = first + 3; i < tokens.length; i++) {
- argType(stringTypeToDexType(tokens[i]));
- }
- methodEnd();
- }
-
- private DexType stringTypeToDexType(String stringType) {
- return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringType));
- }
-
- private int parseModifiers(String[] split) {
- int index = 0;
- while (modifiers.containsKey(split[index])) {
- modifier(modifiers.get(split[index]));
- index++;
- }
- return index;
- }
-
- protected abstract void methodStart();
-
- protected abstract void methodEnd();
-
- protected abstract void returnType(DexType type);
-
- protected abstract void argType(DexType type);
-
- protected abstract void modifier(int access);
-
- protected abstract void holderType(DexType type);
-
- protected abstract void methodName(DexString name);
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 2eb550b..461fdbf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -8,10 +8,13 @@
import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.isHumanSpecification;
import com.android.tools.r8.StringResource;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser.HumanFieldParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser.HumanMethodParser;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -48,6 +51,7 @@
static final String WRAPPER_CONVERSION_EXCLUDING_KEY = "wrapper_conversion_excluding";
static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
static final String REWRITE_PREFIX_KEY = "rewrite_prefix";
+ static final String RETARGET_STATIC_FIELD_KEY = "retarget_static_field";
static final String RETARGET_METHOD_KEY = "retarget_method";
static final String RETARGET_METHOD_EMULATED_DISPATCH_KEY =
"retarget_method_with_emulated_dispatch";
@@ -57,11 +61,13 @@
static final String DONT_RETARGET_KEY = "dont_retarget";
static final String BACKPORT_KEY = "backport";
static final String AMEND_LIBRARY_METHOD_KEY = "amend_library_method";
+ static final String AMEND_LIBRARY_FIELD_KEY = "amend_library_field";
static final String SHRINKER_CONFIG_KEY = "shrinker_config";
static final String SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY = "support_all_callbacks_from_library";
private final DexItemFactory dexItemFactory;
private final HumanMethodParser methodParser;
+ private final HumanFieldParser fieldParser;
private final Reporter reporter;
private final boolean libraryCompilation;
private final int minAPILevel;
@@ -76,6 +82,7 @@
int minAPILevel) {
this.dexItemFactory = dexItemFactory;
this.methodParser = new HumanMethodParser(dexItemFactory);
+ this.fieldParser = new HumanFieldParser(dexItemFactory);
this.reporter = reporter;
this.minAPILevel = minAPILevel;
this.libraryCompilation = libraryCompilation;
@@ -245,6 +252,14 @@
}
}
}
+ if (jsonFlagSet.has(RETARGET_STATIC_FIELD_KEY)) {
+ for (Map.Entry<String, JsonElement> retarget :
+ jsonFlagSet.get(RETARGET_STATIC_FIELD_KEY).getAsJsonObject().entrySet()) {
+ builder.retargetStaticField(
+ parseField(retarget.getKey()),
+ stringDescriptorToDexType(retarget.getValue().getAsString()));
+ }
+ }
if (jsonFlagSet.has(RETARGET_METHOD_KEY)) {
for (Map.Entry<String, JsonElement> retarget :
jsonFlagSet.get(RETARGET_METHOD_KEY).getAsJsonObject().entrySet()) {
@@ -317,6 +332,13 @@
builder.amendLibraryMethod(methodParser.getMethod(), methodParser.getFlags());
}
}
+ if (jsonFlagSet.has(AMEND_LIBRARY_FIELD_KEY)) {
+ JsonArray amendLibraryMember = jsonFlagSet.get(AMEND_LIBRARY_FIELD_KEY).getAsJsonArray();
+ for (JsonElement amend : amendLibraryMember) {
+ fieldParser.parseField(amend.getAsString());
+ builder.amendLibraryField(fieldParser.getField(), fieldParser.getFlags());
+ }
+ }
}
private Set<DexMethod> parseMethods(JsonArray array) {
@@ -332,6 +354,11 @@
return methodParser.getMethod();
}
+ private DexField parseField(String signature) {
+ fieldParser.parseField(signature);
+ return fieldParser.getField();
+ }
+
private DexType stringDescriptorToDexType(String stringClass) {
return dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 9eb3ed7..6d22218 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Reporter;
@@ -26,6 +28,7 @@
private final Map<String, String> rewritePrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexField, DexType> retargetStaticField;
private final Map<DexMethod, DexType> retargetMethod;
private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
private final Map<DexType, DexType> legacyBackport;
@@ -34,11 +37,13 @@
private final Set<DexType> dontRetarget;
private final Map<DexType, Set<DexMethod>> wrapperConversions;
private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
+ private final Map<DexField, FieldAccessFlags> amendLibraryField;
HumanRewritingFlags(
Map<String, String> rewritePrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
+ Map<DexField, DexType> retargetStaticField,
Map<DexMethod, DexType> retargetMethod,
Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
Map<DexType, DexType> legacyBackport,
@@ -46,10 +51,12 @@
Set<DexMethod> dontRewriteInvocation,
Set<DexType> dontRetarget,
Map<DexType, Set<DexMethod>> wrapperConversion,
- Map<DexMethod, MethodAccessFlags> amendLibraryMethod) {
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField) {
this.rewritePrefix = rewritePrefix;
this.rewriteDerivedPrefix = rewriteDerivedPrefix;
this.emulatedInterfaces = emulateLibraryInterface;
+ this.retargetStaticField = retargetStaticField;
this.retargetMethod = retargetMethod;
this.retargetMethodEmulatedDispatch = retargetMethodEmulatedDispatch;
this.legacyBackport = legacyBackport;
@@ -58,6 +65,7 @@
this.dontRetarget = dontRetarget;
this.wrapperConversions = wrapperConversion;
this.amendLibraryMethod = amendLibraryMethod;
+ this.amendLibraryField = amendLibraryField;
}
public static HumanRewritingFlags empty() {
@@ -69,9 +77,11 @@
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
+ ImmutableMap.of(),
ImmutableSet.of(),
ImmutableSet.of(),
ImmutableMap.of(),
+ ImmutableMap.of(),
ImmutableMap.of());
}
@@ -86,6 +96,7 @@
rewritePrefix,
rewriteDerivedPrefix,
emulatedInterfaces,
+ retargetStaticField,
retargetMethod,
retargetMethodEmulatedDispatch,
legacyBackport,
@@ -93,7 +104,8 @@
dontRewriteInvocation,
dontRetarget,
wrapperConversions,
- amendLibraryMethod);
+ amendLibraryMethod,
+ amendLibraryField);
}
public Map<String, String> getRewritePrefix() {
@@ -108,6 +120,10 @@
return emulatedInterfaces;
}
+ public Map<DexField, DexType> getRetargetStaticField() {
+ return retargetStaticField;
+ }
+
public Map<DexMethod, DexType> getRetargetMethod() {
return retargetMethod;
}
@@ -140,11 +156,17 @@
return amendLibraryMethod;
}
+ public Map<DexField, FieldAccessFlags> getAmendLibraryField() {
+ return amendLibraryField;
+ }
+
public boolean isEmpty() {
return rewritePrefix.isEmpty()
&& rewriteDerivedPrefix.isEmpty()
&& emulatedInterfaces.isEmpty()
- && retargetMethod.isEmpty();
+ && retargetMethod.isEmpty()
+ && retargetMethodEmulatedDispatch.isEmpty()
+ && retargetStaticField.isEmpty();
}
public static class Builder {
@@ -155,6 +177,7 @@
private final Map<String, String> rewritePrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexField, DexType> retargetStaticField;
private final Map<DexMethod, DexType> retargetMethod;
private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
private final Map<DexType, DexType> legacyBackport;
@@ -163,6 +186,7 @@
private final Set<DexType> dontRetarget;
private final Map<DexType, Set<DexMethod>> wrapperConversions;
private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
+ private final Map<DexField, FieldAccessFlags> amendLibraryField;
Builder(Reporter reporter, Origin origin) {
this(
@@ -175,9 +199,11 @@
new IdentityHashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
+ new IdentityHashMap<>(),
Sets.newIdentityHashSet(),
Sets.newIdentityHashSet(),
new IdentityHashMap<>(),
+ new IdentityHashMap<>(),
new IdentityHashMap<>());
}
@@ -187,6 +213,7 @@
Map<String, String> rewritePrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
+ Map<DexField, DexType> retargetStaticField,
Map<DexMethod, DexType> retargetMethod,
Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
Map<DexType, DexType> backportCoreLibraryMember,
@@ -194,12 +221,14 @@
Set<DexMethod> dontRewriteInvocation,
Set<DexType> dontRetargetLibMember,
Map<DexType, Set<DexMethod>> wrapperConversions,
- Map<DexMethod, MethodAccessFlags> amendLibrary) {
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField) {
this.reporter = reporter;
this.origin = origin;
this.rewritePrefix = new HashMap<>(rewritePrefix);
this.rewriteDerivedPrefix = new HashMap<>(rewriteDerivedPrefix);
this.emulatedInterfaces = new IdentityHashMap<>(emulateLibraryInterface);
+ this.retargetStaticField = new IdentityHashMap<>(retargetStaticField);
this.retargetMethod = new IdentityHashMap<>(retargetMethod);
this.retargetMethodEmulatedDispatch = new IdentityHashMap<>(retargetMethodEmulatedDispatch);
this.legacyBackport = new IdentityHashMap<>(backportCoreLibraryMember);
@@ -209,7 +238,8 @@
this.dontRetarget = Sets.newIdentityHashSet();
this.dontRetarget.addAll(dontRetargetLibMember);
this.wrapperConversions = new IdentityHashMap<>(wrapperConversions);
- this.amendLibraryMethod = new IdentityHashMap<>(amendLibrary);
+ this.amendLibraryMethod = new IdentityHashMap<>(amendLibraryMethod);
+ this.amendLibraryField = new IdentityHashMap<>(amendLibraryField);
}
// Utility to set values.
@@ -285,6 +315,15 @@
return this;
}
+ public Builder retargetStaticField(DexField key, DexType rewrittenType) {
+ put(
+ retargetStaticField,
+ key,
+ rewrittenType,
+ HumanDesugaredLibrarySpecificationParser.RETARGET_STATIC_FIELD_KEY);
+ return this;
+ }
+
public Builder retargetMethodEmulatedDispatch(DexMethod key, DexType rewrittenType) {
put(
retargetMethodEmulatedDispatch,
@@ -318,12 +357,18 @@
return this;
}
+ public Builder amendLibraryField(DexField member, FieldAccessFlags flags) {
+ amendLibraryField.put(member, flags);
+ return this;
+ }
+
public HumanRewritingFlags build() {
validate();
return new HumanRewritingFlags(
ImmutableMap.copyOf(rewritePrefix),
ImmutableMap.copyOf(rewriteDerivedPrefix),
ImmutableMap.copyOf(emulatedInterfaces),
+ ImmutableMap.copyOf(retargetStaticField),
ImmutableMap.copyOf(retargetMethod),
ImmutableMap.copyOf(retargetMethodEmulatedDispatch),
ImmutableMap.copyOf(legacyBackport),
@@ -331,7 +376,8 @@
ImmutableSet.copyOf(dontRewriteInvocation),
ImmutableSet.copyOf(dontRetarget),
ImmutableMap.copyOf(wrapperConversions),
- ImmutableMap.copyOf(amendLibraryMethod));
+ ImmutableMap.copyOf(amendLibraryMethod),
+ ImmutableMap.copyOf(amendLibraryField));
}
private void validate() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
index 6f1f435..5383b69 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
@@ -47,7 +47,7 @@
public static HumanTopLevelFlags testing() {
return new HumanTopLevelFlags(
- AndroidApiLevel.R, "unused", "testing", null, true, ImmutableList.of());
+ AndroidApiLevel.O, "unused", "testing", null, true, ImmutableList.of());
}
public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java
new file mode 100644
index 0000000..8062063
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java
@@ -0,0 +1,43 @@
+// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+
+/** Parse fields of the form: modifiers* fieldType holder#fieldName */
+public abstract class AbstractFieldParser extends AbstractMemberParser {
+
+ protected AbstractFieldParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
+ // method instead, then add a TraversalContinuation.
+ public void parseField(String signature) {
+ String[] tokens = signature.split(SEPARATORS);
+ if (tokens.length < 3) {
+ throw new CompilationError("Desugared library: cannot parse field " + signature);
+ }
+ fieldStart();
+ int first = parseModifiers(tokens);
+ fieldType(stringTypeToDexType(tokens[first]));
+ holderType(stringTypeToDexType(tokens[first + 1]));
+ fieldName(factory.createString(tokens[first + 1 + 1]));
+ fieldEnd();
+ }
+
+ protected abstract void fieldStart();
+
+ protected abstract void fieldEnd();
+
+ protected abstract void fieldType(DexType type);
+
+ protected abstract void holderType(DexType type);
+
+ protected abstract void fieldName(DexString name);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java
new file mode 100644
index 0000000..99475b2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java
@@ -0,0 +1,48 @@
+// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+
+public abstract class AbstractMemberParser {
+
+ static final String SEPARATORS = "\\s+|,\\s+|#|\\(|\\)";
+
+ static final Map<String, Integer> MODIFIERS =
+ ImmutableMap.<String, Integer>builder()
+ .put("public", Constants.ACC_PUBLIC)
+ .put("private", Constants.ACC_PRIVATE)
+ .put("protected", Constants.ACC_PROTECTED)
+ .put("final", Constants.ACC_FINAL)
+ .put("abstract", Constants.ACC_ABSTRACT)
+ .put("static", Constants.ACC_STATIC)
+ .build();
+
+ final DexItemFactory factory;
+
+ protected AbstractMemberParser(DexItemFactory factory) {
+ this.factory = factory;
+ }
+
+ DexType stringTypeToDexType(String stringType) {
+ return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringType));
+ }
+
+ int parseModifiers(String[] split) {
+ int index = 0;
+ while (MODIFIERS.containsKey(split[index])) {
+ modifier(MODIFIERS.get(split[index]));
+ index++;
+ }
+ return index;
+ }
+
+ protected abstract void modifier(int access);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java
new file mode 100644
index 0000000..1afff88
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java
@@ -0,0 +1,48 @@
+// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+
+/** Parse methods of the form: modifiers* returnType holder#name(arg0, ..., argN) */
+public abstract class AbstractMethodParser extends AbstractMemberParser {
+
+ protected AbstractMethodParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
+ // method instead, then add a TraversalContinuation.
+ public void parseMethod(String signature) {
+ String[] tokens = signature.split(SEPARATORS);
+ if (tokens.length < 3) {
+ throw new CompilationError("Desugared library: cannot parse method " + signature);
+ }
+ methodStart();
+ int first = parseModifiers(tokens);
+ returnType(stringTypeToDexType(tokens[first]));
+ holderType(stringTypeToDexType(tokens[first + 1]));
+ methodName(factory.createString(tokens[first + 1 + 1]));
+ for (int i = first + 3; i < tokens.length; i++) {
+ argType(stringTypeToDexType(tokens[i]));
+ }
+ methodEnd();
+ }
+
+ protected abstract void methodStart();
+
+ protected abstract void methodEnd();
+
+ protected abstract void returnType(DexType type);
+
+ protected abstract void argType(DexType type);
+
+ protected abstract void holderType(DexType type);
+
+ protected abstract void methodName(DexString name);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java
new file mode 100644
index 0000000..9a5a44d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java
@@ -0,0 +1,81 @@
+// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
+
+public class HumanFieldParser extends AbstractFieldParser {
+
+ // Values accumulated while parsing.
+ private FieldAccessFlags.Builder flagBuilder;
+ private DexType fieldType;
+ private DexType holder;
+ private DexString fieldName;
+ // Resulting values.
+ private DexField field;
+ private FieldAccessFlags flags;
+
+ public HumanFieldParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ private boolean parsingFinished() {
+ return field != null;
+ }
+
+ public DexField getField() {
+ assert parsingFinished();
+ return field;
+ }
+
+ public FieldAccessFlags getFlags() {
+ assert parsingFinished();
+ return flags;
+ }
+
+ @Override
+ protected void modifier(int access) {
+ assert !parsingFinished();
+ flagBuilder.set(access);
+ }
+
+ @Override
+ protected void holderType(DexType type) {
+ assert !parsingFinished();
+ holder = type;
+ }
+
+ @Override
+ protected void fieldName(DexString name) {
+ assert !parsingFinished();
+ fieldName = name;
+ }
+
+ @Override
+ protected void fieldStart() {
+ flagBuilder = FieldAccessFlags.builder();
+ fieldType = null;
+ holder = null;
+ fieldName = null;
+ field = null;
+ flags = null;
+ }
+
+ @Override
+ protected void fieldEnd() {
+ field = factory.createField(holder, fieldType, fieldName);
+ flags = flagBuilder.build();
+ }
+
+ @Override
+ protected void fieldType(DexType type) {
+ assert !parsingFinished();
+ fieldType = type;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
index b4bac60..d78267b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
@@ -2,7 +2,7 @@
// 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.ir.desugar.desugaredlibrary.humanspecification;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -25,7 +25,7 @@
private DexMethod method;
private MethodAccessFlags flags;
- protected HumanMethodParser(DexItemFactory factory) {
+ public HumanMethodParser(DexItemFactory factory) {
super(factory);
}
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 1f52b3d..5216a03 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
@@ -4,9 +4,11 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.SemanticVersion;
@@ -86,6 +88,10 @@
return rewritingFlags.getRewriteDerivedTypeOnly();
}
+ public Map<DexField, DexField> getStaticFieldRetarget() {
+ return rewritingFlags.getStaticFieldRetarget();
+ }
+
public Map<DexMethod, DexMethod> getStaticRetarget() {
return rewritingFlags.getStaticRetarget();
}
@@ -143,6 +149,10 @@
return rewritingFlags.getAmendLibraryMethod();
}
+ public Map<DexField, FieldAccessFlags> getAmendLibraryFields() {
+ return rewritingFlags.getAmendLibraryField();
+ }
+
public boolean hasRetargeting() {
return rewritingFlags.hasRetargeting();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index 00a4747..bc566af3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -26,6 +28,7 @@
MachineRewritingFlags(
Map<DexType, DexType> rewriteType,
Map<DexType, DexType> rewriteDerivedTypeOnly,
+ Map<DexField, DexField> staticFieldRetarget,
Map<DexMethod, DexMethod> staticRetarget,
Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget,
@@ -35,9 +38,11 @@
Map<DexType, DexType> legacyBackport,
Set<DexType> dontRetarget,
Map<DexType, CustomConversionDescriptor> customConversions,
- Map<DexMethod, MethodAccessFlags> amendLibraryMethods) {
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethods,
+ Map<DexField, FieldAccessFlags> amendLibraryFields) {
this.rewriteType = rewriteType;
this.rewriteDerivedTypeOnly = rewriteDerivedTypeOnly;
+ this.staticFieldRetarget = staticFieldRetarget;
this.staticRetarget = staticRetarget;
this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
this.emulatedVirtualRetarget = emulatedVirtualRetarget;
@@ -49,6 +54,7 @@
this.dontRetarget = dontRetarget;
this.customConversions = customConversions;
this.amendLibraryMethod = amendLibraryMethods;
+ this.amendLibraryField = amendLibraryFields;
}
// Rewrites all the references to the keys as well as synthetic types derived from any key.
@@ -56,7 +62,10 @@
// Rewrites only synthetic types derived from any key.
private final Map<DexType, DexType> rewriteDerivedTypeOnly;
- // Static methods to retarget, duplicated to library boundaries.
+ // Fields to retarget.
+ private final Map<DexField, DexField> staticFieldRetarget;
+
+ // Static methods to retarget.
private final Map<DexMethod, DexMethod> staticRetarget;
// Virtual methods to retarget, which are guaranteed not to require emulated dispatch.
@@ -83,6 +92,7 @@
private final Set<DexType> dontRetarget;
private final Map<DexType, CustomConversionDescriptor> customConversions;
private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
+ private final Map<DexField, FieldAccessFlags> amendLibraryField;
public Map<DexType, DexType> getRewriteType() {
return rewriteType;
@@ -92,6 +102,10 @@
return rewriteDerivedTypeOnly;
}
+ public Map<DexField, DexField> getStaticFieldRetarget() {
+ return staticFieldRetarget;
+ }
+
public Map<DexMethod, DexMethod> getStaticRetarget() {
return staticRetarget;
}
@@ -146,10 +160,15 @@
return amendLibraryMethod;
}
+ public Map<DexField, FieldAccessFlags> getAmendLibraryField() {
+ return amendLibraryField;
+ }
+
public boolean hasRetargeting() {
return !staticRetarget.isEmpty()
|| !nonEmulatedVirtualRetarget.isEmpty()
- || !emulatedVirtualRetarget.isEmpty();
+ || !emulatedVirtualRetarget.isEmpty()
+ || !staticFieldRetarget.isEmpty();
}
public boolean isEmulatedInterfaceRewrittenType(DexType type) {
@@ -175,6 +194,8 @@
private final Map<DexType, DexType> rewriteType = new IdentityHashMap<>();
private final Map<DexType, DexType> rewriteDerivedTypeOnly = new IdentityHashMap<>();
+ private final ImmutableMap.Builder<DexField, DexField> staticFieldRetarget =
+ ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, DexMethod> staticRetarget =
ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, DexMethod> nonEmulatedVirtualRetarget =
@@ -192,6 +213,8 @@
ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, MethodAccessFlags> amendLibraryMethod =
ImmutableMap.builder();
+ private final ImmutableMap.Builder<DexField, FieldAccessFlags> amendLibraryField =
+ ImmutableMap.builder();
public void rewriteType(DexType src, DexType target) {
assert src != null;
@@ -205,6 +228,10 @@
rewriteDerivedTypeOnly.put(src, target);
}
+ public void putStaticFieldRetarget(DexField src, DexField dest) {
+ staticFieldRetarget.put(src, dest);
+ }
+
public void putStaticRetarget(DexMethod src, DexMethod dest) {
staticRetarget.put(src, dest);
}
@@ -245,6 +272,10 @@
amendLibraryMethod.put(missingReference, flags);
}
+ public void amendLibraryField(DexField missingReference, FieldAccessFlags flags) {
+ amendLibraryField.put(missingReference, flags);
+ }
+
public DexType getRewrittenType(DexType type) {
return rewriteType.get(type);
}
@@ -253,6 +284,7 @@
return new MachineRewritingFlags(
rewriteType,
rewriteDerivedTypeOnly,
+ staticFieldRetarget.build(),
staticRetarget.build(),
nonEmulatedVirtualRetarget.build(),
emulatedVirtualRetarget.build(),
@@ -262,7 +294,8 @@
legacyBackport.build(),
dontRetarget.build(),
customConversions.build(),
- amendLibraryMethod.build());
+ amendLibraryMethod.build(),
+ amendLibraryField.build());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index a4b984f..a929fb9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -6,12 +6,15 @@
import static com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter.InvokeRetargetingResult.NO_REWRITING;
+import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.MethodResolutionResult;
@@ -26,6 +29,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -36,6 +40,7 @@
private final AppView<?> appView;
private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
+ private final Map<DexField, DexField> staticFieldRetarget;
private final Map<DexMethod, DexMethod> staticRetarget;
private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
@@ -45,6 +50,7 @@
this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
MachineDesugaredLibrarySpecification specification =
appView.options().machineDesugaredLibrarySpecification;
+ staticFieldRetarget = specification.getStaticFieldRetarget();
staticRetarget = specification.getStaticRetarget();
nonEmulatedVirtualRetarget = specification.getNonEmulatedVirtualRetarget();
emulatedVirtualRetarget = specification.getEmulatedVirtualRetarget();
@@ -67,20 +73,53 @@
MethodProcessingContext methodProcessingContext,
CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
- InvokeRetargetingResult invokeRetargetingResult = computeNewInvokeTarget(instruction, context);
-
- if (!invokeRetargetingResult.hasNewInvokeTarget()) {
- return null;
+ if (instruction.isFieldInstruction() && needsDesugaring(instruction, context)) {
+ return desugarFieldInstruction(instruction.asFieldInstruction(), context);
+ } else if (instruction.isInvoke() && needsDesugaring(instruction, context)) {
+ return desugarInvoke(instruction.asInvoke(), eventConsumer, context);
}
+ return null;
+ }
+ private Collection<CfInstruction> desugarFieldInstruction(
+ CfFieldInstruction fieldInstruction, ProgramMethod context) {
+ DexField fieldRetarget = fieldRetarget(fieldInstruction, context);
+ assert fieldRetarget != null;
+ assert fieldInstruction.isStaticFieldGet() || fieldInstruction.isStaticFieldPut();
+ return Collections.singletonList(fieldInstruction.createWithField(fieldRetarget));
+ }
+
+ private List<CfInstruction> desugarInvoke(
+ CfInvoke invoke, CfInstructionDesugaringEventConsumer eventConsumer, ProgramMethod context) {
+ InvokeRetargetingResult invokeRetargetingResult = computeNewInvokeTarget(invoke, context);
+ assert invokeRetargetingResult.hasNewInvokeTarget();
DexMethod newInvokeTarget = invokeRetargetingResult.getNewInvokeTarget(eventConsumer);
return Collections.singletonList(
- new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, instruction.asInvoke().isInterface()));
+ new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, invoke.isInterface()));
}
@Override
public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
- return computeNewInvokeTarget(instruction, context).hasNewInvokeTarget();
+ if (instruction.isFieldInstruction()) {
+ return fieldRetarget(instruction.asFieldInstruction(), context) != null;
+ } else if (instruction.isInvoke()) {
+ return computeNewInvokeTarget(instruction.asInvoke(), context).hasNewInvokeTarget();
+ }
+ return false;
+ }
+
+ private DexField fieldRetarget(CfFieldInstruction fieldInstruction, ProgramMethod context) {
+ DexEncodedField resolvedField =
+ appView
+ .appInfoForDesugaring()
+ .resolveField(fieldInstruction.getField(), context)
+ .getResolvedField();
+ if (resolvedField != null) {
+ assert resolvedField.isStatic()
+ || !staticFieldRetarget.containsKey(resolvedField.getReference());
+ return staticFieldRetarget.get(resolvedField.getReference());
+ }
+ return null;
}
InvokeRetargetingResult ensureInvokeRetargetingResult(DexMethod retarget) {
@@ -124,10 +163,7 @@
}
private InvokeRetargetingResult computeNewInvokeTarget(
- CfInstruction instruction, ProgramMethod context) {
- if (!instruction.isInvoke()) {
- return NO_REWRITING;
- }
+ CfInvoke instruction, ProgramMethod context) {
if (appView
.options()
.machineDesugaredLibrarySpecification
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index f64a3d0..56af1fc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -6,7 +6,9 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexReference;
@@ -26,7 +28,7 @@
public class HumanToMachineRetargetConverter {
private final AppInfoWithClassHierarchy appInfo;
- private final Set<DexMethod> missingMethods = Sets.newIdentityHashSet();
+ private final Set<DexReference> missingReferences = Sets.newIdentityHashSet();
public HumanToMachineRetargetConverter(AppInfoWithClassHierarchy appInfo) {
this.appInfo = appInfo;
@@ -37,6 +39,9 @@
MachineRewritingFlags.Builder builder,
BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
rewritingFlags
+ .getRetargetStaticField()
+ .forEach((field, type) -> convertRetargetField(builder, field, type));
+ rewritingFlags
.getRetargetMethod()
.forEach((method, type) -> convertRetargetMethod(builder, method, type));
rewritingFlags
@@ -44,7 +49,19 @@
.forEach(
(method, type) ->
convertRetargetMethodEmulatedDispatch(builder, rewritingFlags, method, type));
- warnConsumer.accept("Cannot retarget missing methods: ", missingMethods);
+ warnConsumer.accept("Cannot retarget missing references: ", missingReferences);
+ }
+
+ private void convertRetargetField(
+ MachineRewritingFlags.Builder builder, DexField field, DexType type) {
+ DexClass holder = appInfo.definitionFor(field.holder);
+ DexEncodedField foundField = holder.lookupField(field);
+ if (foundField == null) {
+ missingReferences.add(field);
+ return;
+ }
+ builder.putStaticFieldRetarget(
+ field, appInfo.dexItemFactory().createField(type, field.type, field.name));
}
private void convertRetargetMethodEmulatedDispatch(
@@ -55,7 +72,7 @@
DexClass holder = appInfo.definitionFor(method.holder);
DexEncodedMethod foundMethod = holder.lookupMethod(method);
if (foundMethod == null) {
- missingMethods.add(method);
+ missingReferences.add(method);
return;
}
if (foundMethod.isStatic()) {
@@ -83,7 +100,7 @@
DexClass holder = appInfo.definitionFor(method.holder);
DexEncodedMethod foundMethod = holder.lookupMethod(method);
if (foundMethod == null) {
- missingMethods.add(method);
+ missingReferences.add(method);
return;
}
if (foundMethod.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index 5ea225d..0cec776 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -86,8 +86,13 @@
HumanRewritingFlags rewritingFlags = humanSpec.getRewritingFlags();
MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
DesugaredLibraryAmender.run(
- rewritingFlags.getAmendLibraryMethod(), appInfo, reporter, ComputedApiLevel.unknown());
+ rewritingFlags.getAmendLibraryMethod(),
+ rewritingFlags.getAmendLibraryField(),
+ appInfo,
+ reporter,
+ ComputedApiLevel.unknown());
rewritingFlags.getAmendLibraryMethod().forEach(builder::amendLibraryMethod);
+ rewritingFlags.getAmendLibraryField().forEach(builder::amendLibraryField);
new HumanToMachineRetargetConverter(appInfo)
.convertRetargetFlags(rewritingFlags, builder, this::warnMissingReferences);
new HumanToMachineEmulatedInterfaceConverter(appInfo)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java
new file mode 100644
index 0000000..23a146e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java
@@ -0,0 +1,132 @@
+// 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.desugar.desugaredlibrary;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.util.Collection;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class LocalDateEpochTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("1970-01-01");
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V8_1_0)
+ .withAllApiLevels()
+ .build();
+ }
+
+ public LocalDateEpochTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addProgramClasses(DesugarLocalDate.class)
+ .addProgramClassFileData(getMainClassFileData())
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(opt -> opt.setDesugaredLibrarySpecification(getSpecification(opt)))
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Assume.assumeTrue(parameters.isDexRuntime());
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addProgramClasses(DesugarLocalDate.class)
+ .addProgramClassFileData(getMainClassFileData())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(opt -> opt.setDesugaredLibrarySpecification(getSpecification(opt)))
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ private DesugaredLibrarySpecification getSpecification(InternalOptions options) {
+ DexType date = options.dexItemFactory().createType("Ljava/time/LocalDate;");
+ DexType desugarDate =
+ options
+ .dexItemFactory()
+ .createType("L" + DescriptorUtils.getClassBinaryName(DesugarLocalDate.class) + ";");
+ DexString epoch = options.dexItemFactory().createString("EPOCH");
+ DexField src = options.dexItemFactory().createField(date, date, epoch);
+ HumanRewritingFlags rewritingFlags =
+ HumanRewritingFlags.builder(options.reporter, Origin.unknown())
+ .retargetStaticField(src, desugarDate)
+ .amendLibraryField(
+ src,
+ FieldAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_FINAL))
+ .build();
+ return new HumanDesugaredLibrarySpecification(
+ HumanTopLevelFlags.testing(), rewritingFlags, false);
+ }
+
+ private Collection<byte[]> getMainClassFileData() throws IOException {
+ return ImmutableList.of(
+ transformer(Main.class)
+ .addMethodTransformer(
+ new MethodTransformer() {
+ @Override
+ public void visitFieldInsn(
+ final int opcode,
+ final String owner,
+ final String name,
+ final String descriptor) {
+ if (name.equals("MIN")) {
+ super.visitFieldInsn(opcode, owner, "EPOCH", descriptor);
+ } else {
+ super.visitFieldInsn(opcode, owner, name, descriptor);
+ }
+ }
+ })
+ .transform());
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(LocalDate.MIN);
+ }
+ }
+
+ static class DesugarLocalDate {
+
+ public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
+ }
+}