Rewrite objects argument of newMessageInfo()
Bug: 112437944
Change-Id: Ib50cb97678993ade99d30ae3476d347d8e1694e8
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index c0eee4f..0fbeef9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -550,6 +550,19 @@
return lookupTarget(instanceFields, field);
}
+ public DexField lookupUniqueInstanceFieldWithName(DexString name) {
+ DexField field = null;
+ for (DexEncodedField encodedField : instanceFields()) {
+ if (encodedField.field.name == name) {
+ if (field != null) {
+ return null;
+ }
+ field = encodedField.field;
+ }
+ }
+ return field;
+ }
+
/**
* Find field in this class matching field.
*/
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
index c7eaa02..7f33fbb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
@@ -6,27 +6,24 @@
import com.android.tools.r8.graph.AppView;
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.DexString;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldTypeFactory;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoMessageInfo;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoObject;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.code.ArrayPut;
+import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstString;
-import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.MemberType;
+import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.naming.dexitembasedstring.FieldNameComputationInfo;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.StringDiagnostic;
-import java.util.ArrayList;
import java.util.List;
public class GeneratedMessageLiteShrinker {
@@ -35,9 +32,11 @@
private final RawMessageInfoDecoder decoder;
private final RawMessageInfoEncoder encoder;
private final ProtoReferences references;
- private final TypeLatticeElement stringType;
private final ThrowingInfo throwingInfo;
+ private final TypeLatticeElement objectArrayType;
+ private final TypeLatticeElement stringType;
+
private final ProtoFieldTypeFactory factory = new ProtoFieldTypeFactory();
public GeneratedMessageLiteShrinker(AppView<AppInfoWithLiveness> appView) {
@@ -45,8 +44,13 @@
this.decoder = new RawMessageInfoDecoder(factory);
this.encoder = new RawMessageInfoEncoder(appView.dexItemFactory());
this.references = appView.protoShrinker().references;
- this.stringType = TypeLatticeElement.stringClassType(appView, Nullability.definitelyNotNull());
this.throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
+
+ // Types.
+ this.objectArrayType =
+ TypeLatticeElement.fromDexType(
+ appView.dexItemFactory().objectArrayType, Nullability.definitelyNotNull(), appView);
+ this.stringType = TypeLatticeElement.stringClassType(appView, Nullability.definitelyNotNull());
}
public void run(DexEncodedMethod method, IRCode code) {
@@ -64,8 +68,8 @@
* newMessageInfo is still pending.
*/
private void rewriteDynamicMethod(DexEncodedMethod method, IRCode code) {
- DexClass clazz = appView.definitionFor(method.method.holder);
- if (clazz == null || !clazz.isProgramClass()) {
+ DexClass context = appView.definitionFor(method.method.holder);
+ if (context == null || !context.isProgramClass()) {
return;
}
@@ -90,46 +94,15 @@
Value infoValue = newMessageInfoInvoke.inValues().get(1).getAliasedValue();
Value objectsValue = newMessageInfoInvoke.inValues().get(2).getAliasedValue();
- // TODO(b/112437944): If we regenerate the arguments to newMessageInfo() entirely, then we can
- // simply generate DexItemBasedConstString instructions at that point. That way the block
- // below will not be needed.
- {
- List<ConstString> identifierNameStringCandidates = new ArrayList<>();
- for (Instruction user : objectsValue.uniqueUsers()) {
- if (user.isArrayPut()) {
- Value rewritingCandidate = user.asArrayPut().value().getAliasedValue();
- if (!rewritingCandidate.isPhi() && rewritingCandidate.definition.isConstString()) {
- identifierNameStringCandidates.add(rewritingCandidate.definition.asConstString());
- }
- }
- }
-
- boolean changed = false;
- for (ConstString rewritingCandidate : identifierNameStringCandidates) {
- DexString fieldName = rewritingCandidate.getValue();
- DexField field = uniqueInstanceFieldWithName(clazz, fieldName, code.origin);
- if (field == null) {
- continue;
- }
- Value newValue = code.createValue(stringType);
- rewritingCandidate.replace(
- new DexItemBasedConstString(
- newValue, field, FieldNameComputationInfo.forFieldName(), throwingInfo));
- changed = true;
- }
-
- if (changed) {
- method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
- }
-
// Decode the arguments passed to newMessageInfo().
- ProtoMessageInfo protoMessageInfo = decoder.run(infoValue, objectsValue);
+ ProtoMessageInfo protoMessageInfo = decoder.run(infoValue, objectsValue, context);
if (protoMessageInfo != null) {
// Rewrite the arguments to newMessageInfo().
- infoValue.definition.replace(
- new ConstString(
- code.createValue(stringType), encoder.encodeInfo(protoMessageInfo), throwingInfo));
+ rewriteArgumentsToNewMessageInfo(
+ method, code, newMessageInfoInvoke, infoValue, protoMessageInfo);
+
+ // TODO(b/112437944): Need to ensure that the definition of the original `objects` value is
+ // removed by dead code elimination.
} else {
// We should generally be able to decode the arguments passed to newMessageInfo().
assert false;
@@ -137,23 +110,63 @@
}
}
- private DexField uniqueInstanceFieldWithName(DexClass clazz, DexString name, Origin origin) {
- DexField field = null;
- for (DexEncodedField encodedField : clazz.instanceFields()) {
- if (encodedField.field.name == name) {
- if (field != null) {
- Reporter reporter = appView.options().reporter;
- String errorMessage =
- "Expected to find a single instance field named \""
- + name.toSourceString()
- + "\" in `"
- + clazz.type.toSourceString()
- + "`";
- throw reporter.fatalError(new StringDiagnostic(errorMessage, origin));
- }
- field = encodedField.field;
+ private void rewriteArgumentsToNewMessageInfo(
+ DexEncodedMethod method,
+ IRCode code,
+ InvokeStatic newMessageInfoInvoke,
+ Value infoValue,
+ ProtoMessageInfo protoMessageInfo) {
+ rewriteInfoArgumentToNewMessageInfo(code, infoValue, protoMessageInfo);
+ rewriteObjectsArgumentToNewMessageInfo(method, code, newMessageInfoInvoke, protoMessageInfo);
+ }
+
+ private void rewriteInfoArgumentToNewMessageInfo(
+ IRCode code, Value infoValue, ProtoMessageInfo protoMessageInfo) {
+ infoValue.definition.replace(
+ new ConstString(
+ code.createValue(stringType), encoder.encodeInfo(protoMessageInfo), throwingInfo));
+ }
+
+ private void rewriteObjectsArgumentToNewMessageInfo(
+ DexEncodedMethod method,
+ IRCode code,
+ InvokeStatic newMessageInfoInvoke,
+ ProtoMessageInfo protoMessageInfo) {
+ // Position iterator immediately before the call to newMessageInfo().
+ BasicBlock block = newMessageInfoInvoke.getBlock();
+ InstructionListIterator instructionIterator = block.listIterator(newMessageInfoInvoke);
+ Instruction previous = instructionIterator.previous();
+ instructionIterator.setInsertionPosition(newMessageInfoInvoke.getPosition());
+ assert previous == newMessageInfoInvoke;
+
+ // Create the `objects` array.
+ List<ProtoObject> objects = encoder.encodeObjects(protoMessageInfo);
+ Value sizeValue =
+ instructionIterator.insertConstIntInstruction(code, appView.options(), objects.size());
+ Value newObjectsValue = code.createValue(objectArrayType);
+ instructionIterator.add(
+ new NewArrayEmpty(newObjectsValue, sizeValue, appView.dexItemFactory().objectArrayType));
+
+ // Populate the `objects` array.
+ boolean hasIntroducedIdentifierNameString = false;
+ for (int i = 0; i < objects.size(); i++) {
+ Value indexValue = instructionIterator.insertConstIntInstruction(code, appView.options(), i);
+ Instruction materializingInstruction = objects.get(i).buildIR(appView, code);
+ instructionIterator.add(materializingInstruction);
+ instructionIterator.add(
+ new ArrayPut(
+ MemberType.OBJECT, newObjectsValue, indexValue, materializingInstruction.outValue()));
+
+ if (materializingInstruction.isDexItemBasedConstString()) {
+ hasIntroducedIdentifierNameString = true;
}
}
- return field;
+
+ // Pass the newly created `objects` array to newMessageInfo().
+ newMessageInfoInvoke.replaceValue(2, newObjectsValue);
+
+ if (hasIntroducedIdentifierNameString) {
+ method.getMutableOptimizationInfo().markUseIdentifierNameString();
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java
index fdc3934..90f6e25 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java
@@ -4,20 +4,35 @@
package com.android.tools.r8.ir.analysis.proto;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldInfo;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldObject;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldType;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldTypeFactory;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoMessageInfo;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoObject;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoObjectFromInvokeStatic;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoObjectFromStaticGet;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoTypeObject;
import com.android.tools.r8.ir.code.ArrayPut;
+import com.android.tools.r8.ir.code.ConstClass;
+import com.android.tools.r8.ir.code.ConstString;
+import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.NewArrayEmpty;
+import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
import com.android.tools.r8.utils.ThrowingCharIterator;
import com.android.tools.r8.utils.ThrowingIntIterator;
import com.android.tools.r8.utils.ThrowingIterator;
import java.io.UTFDataFormatException;
+import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.OptionalInt;
@@ -54,7 +69,7 @@
this.factory = factory;
}
- public ProtoMessageInfo run(Value infoValue, Value objectsValue) {
+ public ProtoMessageInfo run(Value infoValue, Value objectsValue, DexClass context) {
try {
ProtoMessageInfo.Builder builder = ProtoMessageInfo.builder();
ThrowingIntIterator<InvalidRawMessageInfoException> infoIterator =
@@ -95,15 +110,19 @@
builder.setNumberOfOneOfObjects(numberOfOneOfObjects);
for (int i = 0; i < numberOfOneOfObjects; i++) {
builder.addOneOfObject(
- objectIterator.computeNextIfAbsent(this::invalidObjectsFailure),
- objectIterator.computeNextIfAbsent(this::invalidObjectsFailure));
+ createProtoObject(
+ objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), context),
+ createProtoObject(
+ objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), context));
}
}
if (numberOfHasBitsObjects > 0) {
builder.setNumberOfHasBitsObjects(numberOfHasBitsObjects);
for (int i = 0; i < numberOfHasBitsObjects; i++) {
- builder.addHasBitsObject(objectIterator.computeNextIfAbsent(this::invalidObjectsFailure));
+ builder.addHasBitsObject(
+ createProtoObject(
+ objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), context));
}
}
@@ -124,8 +143,11 @@
// Extract field-specific portion of "objects" array.
int numberOfObjects = fieldType.numberOfObjects(isProto2, factory);
try {
- List<Value> fieldObjects = objectIterator.take(numberOfObjects);
- builder.addField(new ProtoFieldInfo(fieldNumber, fieldType, auxData, fieldObjects));
+ List<ProtoObject> objects = new ArrayList<>(numberOfObjects);
+ for (Value value : objectIterator.take(numberOfObjects)) {
+ objects.add(createProtoObject(value, context));
+ }
+ builder.addField(new ProtoFieldInfo(fieldNumber, fieldType, auxData, objects));
} catch (NoSuchElementException e) {
throw new InvalidRawMessageInfoException();
}
@@ -144,6 +166,42 @@
}
}
+ private ProtoObject createProtoObject(Value value, DexClass context)
+ throws InvalidRawMessageInfoException {
+ Value root = value.getAliasedValue();
+ if (!root.isPhi()) {
+ Instruction definition = root.definition;
+ if (definition.isConstClass()) {
+ ConstClass constClass = definition.asConstClass();
+ return new ProtoTypeObject(constClass.getValue());
+ } else if (definition.isConstString()) {
+ ConstString constString = definition.asConstString();
+ DexField field = context.lookupUniqueInstanceFieldWithName(constString.getValue());
+ if (field != null) {
+ return new ProtoFieldObject(field);
+ }
+ } else if (definition.isDexItemBasedConstString()) {
+ DexItemBasedConstString constString = definition.asDexItemBasedConstString();
+ DexReference reference = constString.getItem();
+ NameComputationInfo<?> nameComputationInfo = constString.getNameComputationInfo();
+ if (reference.isDexField()
+ && nameComputationInfo.isFieldNameComputationInfo()
+ && nameComputationInfo.asFieldNameComputationInfo().isForFieldName()) {
+ return new ProtoFieldObject(reference.asDexField());
+ }
+ } else if (definition.isInvokeStatic()) {
+ InvokeStatic invoke = definition.asInvokeStatic();
+ if (invoke.arguments().isEmpty()) {
+ return new ProtoObjectFromInvokeStatic(invoke.getInvokedMethod());
+ }
+ } else if (definition.isStaticGet()) {
+ StaticGet staticGet = definition.asStaticGet();
+ return new ProtoObjectFromStaticGet(staticGet.getField());
+ }
+ }
+ throw new InvalidRawMessageInfoException();
+ }
+
private int invalidInfoFailure() throws InvalidRawMessageInfoException {
throw new InvalidRawMessageInfoException();
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoEncoder.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoEncoder.java
index 8487210..6d94b0c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoEncoder.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoEncoder.java
@@ -9,9 +9,13 @@
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldInfo;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldType;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoMessageInfo;
+import com.android.tools.r8.ir.analysis.proto.schema.ProtoObject;
+import com.android.tools.r8.utils.Pair;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntListIterator;
+import java.util.ArrayList;
+import java.util.List;
public class RawMessageInfoEncoder {
@@ -23,7 +27,7 @@
DexString encodeInfo(ProtoMessageInfo protoMessageInfo) {
IntList info = new IntArrayList();
- info.add(protoMessageInfo.flags());
+ info.add(protoMessageInfo.getFlags());
info.add(protoMessageInfo.numberOfFields());
if (protoMessageInfo.hasFields()) {
@@ -33,7 +37,7 @@
int repeatedFieldCount = 0;
int checkInitialized = 0;
- for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.fields()) {
+ for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.getFields()) {
int fieldNumber = protoFieldInfo.getNumber();
if (fieldNumber < minFieldNumber) {
minFieldNumber = fieldNumber;
@@ -61,7 +65,7 @@
info.add(repeatedFieldCount);
info.add(checkInitialized);
- for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.fields()) {
+ for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.getFields()) {
info.add(protoFieldInfo.getNumber());
info.add(protoFieldInfo.getType().serialize());
if (protoFieldInfo.hasAuxData()) {
@@ -92,6 +96,25 @@
return dexItemFactory.createString(info.size() + numberOfExtraChars, result);
}
+ List<ProtoObject> encodeObjects(ProtoMessageInfo protoMessageInfo) {
+ List<ProtoObject> result = new ArrayList<>();
+ if (protoMessageInfo.numberOfOneOfObjects() > 0) {
+ for (Pair<ProtoObject, ProtoObject> oneOfObject : protoMessageInfo.getOneOfObjects()) {
+ result.add(oneOfObject.getFirst());
+ result.add(oneOfObject.getSecond());
+ }
+ }
+ if (protoMessageInfo.numberOfHasBitsObjects() > 0) {
+ result.addAll(protoMessageInfo.getHasBitsObjects());
+ }
+ if (protoMessageInfo.hasFields()) {
+ for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.getFields()) {
+ result.addAll(protoFieldInfo.getObjects());
+ }
+ }
+ return result;
+ }
+
private static int countBytes(IntList info) {
// We need an extra byte for the terminating '0'.
int result = 1;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
index d701c02..153ea66 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.analysis.proto.schema;
-import com.android.tools.r8.ir.code.Value;
import java.util.List;
import java.util.OptionalInt;
@@ -14,11 +13,10 @@
private final ProtoFieldType type;
private final OptionalInt auxData;
- // TODO(b/112437944): Create an abstract representation of the object values to ensure that this
- // is detached from the IR.
- private final List<Value> objects;
+ private final List<ProtoObject> objects;
- public ProtoFieldInfo(int number, ProtoFieldType type, OptionalInt auxData, List<Value> objects) {
+ public ProtoFieldInfo(
+ int number, ProtoFieldType type, OptionalInt auxData, List<ProtoObject> objects) {
this.number = number;
this.type = type;
this.auxData = auxData;
@@ -38,6 +36,10 @@
return number;
}
+ public List<ProtoObject> getObjects() {
+ return objects;
+ }
+
public ProtoFieldType getType() {
return type;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldObject.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldObject.java
new file mode 100644
index 0000000..c3f7795
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldObject.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2019, 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.analysis.proto.schema;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.ir.analysis.type.Nullability;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
+import com.android.tools.r8.ir.code.DexItemBasedConstString;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.naming.dexitembasedstring.FieldNameComputationInfo;
+
+public class ProtoFieldObject extends ProtoObject {
+
+ private final DexField field;
+
+ public ProtoFieldObject(DexField field) {
+ this.field = field;
+ }
+
+ @Override
+ public Instruction buildIR(AppView<?> appView, IRCode code) {
+ Value value =
+ code.createValue(
+ TypeLatticeElement.stringClassType(appView, Nullability.definitelyNotNull()));
+ return new DexItemBasedConstString(
+ value,
+ field,
+ FieldNameComputationInfo.forFieldName(),
+ ThrowingInfo.defaultForConstString(appView.options()));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java
index 45bfdc0..9098d21 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.analysis.proto.schema;
-import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.Pair;
import java.util.ArrayList;
import java.util.List;
@@ -16,8 +15,8 @@
private int flags;
private List<ProtoFieldInfo> fields;
- private List<Value> hasBitsObjects;
- private List<Pair<Value, Value>> oneOfObjects;
+ private List<ProtoObject> hasBitsObjects;
+ private List<Pair<ProtoObject, ProtoObject>> oneOfObjects;
public void setFlags(int value) {
this.flags = value;
@@ -30,7 +29,7 @@
fields.add(field);
}
- public void addHasBitsObject(Value hasBitsObject) {
+ public void addHasBitsObject(ProtoObject hasBitsObject) {
if (hasBitsObjects == null) {
hasBitsObjects = new ArrayList<>();
}
@@ -43,7 +42,7 @@
}
}
- public void addOneOfObject(Value first, Value second) {
+ public void addOneOfObject(ProtoObject first, ProtoObject second) {
if (oneOfObjects == null) {
oneOfObjects = new ArrayList<>();
}
@@ -64,14 +63,14 @@
private final int flags;
private final List<ProtoFieldInfo> fields;
- private final List<Value> hasBitsObjects;
- private final List<Pair<Value, Value>> oneOfObjects;
+ private final List<ProtoObject> hasBitsObjects;
+ private final List<Pair<ProtoObject, ProtoObject>> oneOfObjects;
private ProtoMessageInfo(
int flags,
List<ProtoFieldInfo> fields,
- List<Value> hasBitsObjects,
- List<Pair<Value, Value>> oneOfObjects) {
+ List<ProtoObject> hasBitsObjects,
+ List<Pair<ProtoObject, ProtoObject>> oneOfObjects) {
this.flags = flags;
this.fields = fields;
this.hasBitsObjects = hasBitsObjects;
@@ -82,14 +81,22 @@
return new ProtoMessageInfo.Builder();
}
- public List<ProtoFieldInfo> fields() {
+ public List<ProtoFieldInfo> getFields() {
return fields;
}
- public int flags() {
+ public int getFlags() {
return flags;
}
+ public List<ProtoObject> getHasBitsObjects() {
+ return hasBitsObjects;
+ }
+
+ public List<Pair<ProtoObject, ProtoObject>> getOneOfObjects() {
+ return oneOfObjects;
+ }
+
public boolean hasFields() {
return fields != null && !fields.isEmpty();
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObject.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObject.java
new file mode 100644
index 0000000..ad3a916
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObject.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, 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.analysis.proto.schema;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+
+public abstract class ProtoObject {
+
+ public abstract Instruction buildIR(AppView<?> appView, IRCode code);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObjectFromInvokeStatic.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObjectFromInvokeStatic.java
new file mode 100644
index 0000000..0812098
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObjectFromInvokeStatic.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2019, 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.analysis.proto.schema;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.analysis.type.Nullability;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.Value;
+import com.google.common.collect.ImmutableList;
+
+public class ProtoObjectFromInvokeStatic extends ProtoObject {
+
+ private final DexMethod method;
+
+ public ProtoObjectFromInvokeStatic(DexMethod method) {
+ this.method = method;
+ }
+
+ @Override
+ public Instruction buildIR(AppView<?> appView, IRCode code) {
+ Value value =
+ code.createValue(
+ TypeLatticeElement.fromDexType(
+ method.proto.returnType, Nullability.maybeNull(), appView));
+ return new InvokeStatic(method, value, ImmutableList.of());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObjectFromStaticGet.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObjectFromStaticGet.java
new file mode 100644
index 0000000..9c14f6c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoObjectFromStaticGet.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2019, 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.analysis.proto.schema;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.ir.analysis.type.Nullability;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.Value;
+
+public class ProtoObjectFromStaticGet extends ProtoObject {
+
+ private final DexField field;
+
+ public ProtoObjectFromStaticGet(DexField field) {
+ this.field = field;
+ }
+
+ @Override
+ public Instruction buildIR(AppView<?> appView, IRCode code) {
+ Value value =
+ code.createValue(
+ TypeLatticeElement.fromDexType(field.type, Nullability.maybeNull(), appView));
+ return new StaticGet(value, field);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoTypeObject.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoTypeObject.java
new file mode 100644
index 0000000..21c37e0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoTypeObject.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, 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.analysis.proto.schema;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+
+public class ProtoTypeObject extends ProtoObject {
+
+ private final DexType type;
+
+ public ProtoTypeObject(DexType type) {
+ this.type = type;
+ }
+
+ @Override
+ public Instruction buildIR(AppView<?> appView, IRCode code) {
+ return code.createConstClass(appView, type);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index 2faa999..698592d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -97,7 +97,7 @@
public void add(Instruction instruction) {
instruction.setBlock(block);
assert instruction.getBlock() == block;
- if (position != null) {
+ if (position != null && !instruction.hasPosition()) {
instruction.setPosition(position);
}
listIterator.add(instruction);
@@ -194,6 +194,15 @@
}
@Override
+ public Value insertConstIntInstruction(IRCode code, InternalOptions options, int value) {
+ ConstNumber constNumberInstruction = code.createIntConstant(value);
+ // Note that we only keep position info for throwing instructions in release mode.
+ constNumberInstruction.setPosition(options.debug ? current.getPosition() : Position.none());
+ add(constNumberInstruction);
+ return constNumberInstruction.outValue();
+ }
+
+ @Override
public void replaceCurrentInstructionWithThrowNull(
AppView<? extends AppInfoWithSubtyping> appView,
IRCode code,
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 2e9986b..a1c77dc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -871,6 +871,12 @@
return blocks.stream().max(Comparator.comparingInt(BasicBlock::getNumber)).get().getNumber();
}
+ public ConstClass createConstClass(AppView<?> appView, DexType type) {
+ Value out =
+ createValue(TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appView));
+ return new ConstClass(out, type);
+ }
+
public ConstNumber createConstNull() {
Value out = createValue(TypeLatticeElement.NULL);
return new ConstNumber(out, 0);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index e490ebf..ad70ced 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -65,6 +65,10 @@
public abstract <T> T accept(InstructionVisitor<T> visitor);
+ final boolean hasPosition() {
+ return position != null;
+ }
+
public final Position getPosition() {
assert position != null;
return position;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index 4bb3984..59a77a1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -51,6 +51,8 @@
Value insertConstNullInstruction(IRCode code, InternalOptions options);
+ Value insertConstIntInstruction(IRCode code, InternalOptions options, int value);
+
/**
* Replace the current instruction with null throwing instructions.
*
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java
index 142933f..c14da47 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java
@@ -42,6 +42,11 @@
}
@Override
+ public Value insertConstIntInstruction(IRCode code, InternalOptions options, int value) {
+ return currentBlockIterator.insertConstIntInstruction(code, options, value);
+ }
+
+ @Override
public void replaceCurrentInstructionWithThrowNull(
AppView<? extends AppInfoWithSubtyping> appView,
IRCode code,
diff --git a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/FieldNameComputationInfo.java b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/FieldNameComputationInfo.java
index f9f8cc0..eeb70f3 100644
--- a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/FieldNameComputationInfo.java
+++ b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/FieldNameComputationInfo.java
@@ -21,6 +21,10 @@
return FIELD_NAME_INSTANCE;
}
+ public boolean isForFieldName() {
+ return true;
+ }
+
@Override
public DexString internalComputeNameFor(
DexField field, DexDefinitionSupplier definitions, NamingLens namingLens) {
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index f5c2f27..2971cf9 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -39,6 +39,9 @@
.addProgramFiles(PROTO2_EXAMPLES_JAR, PROTO2_PROTO_JAR, PROTOBUF_LITE_JAR)
.addKeepMainRule("proto2.TestClass")
.addKeepRules(
+ // TODO(b/112437944): Should rewrite constructor calls to RawMessageInfo when
+ // newMessageInfo() is inlined.
+ "-neverinline class * { newMessageInfo(...); }",
// TODO(b/112437944): Do not remove proto fields that are actually used in tree shaking.
"-keepclassmembers,allowobfuscation class * extends",
" com.google.protobuf.GeneratedMessageLite {",
@@ -55,6 +58,7 @@
// Because there are unused rules in lite_proguard.pgcfg.
options.testing.allowUnusedProguardConfigurationRules = true;
})
+ .enableProguardTestOptions()
.minification(enableMinification)
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index 80aae46..e83a89f 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -53,6 +53,11 @@
}
@Override
+ public Value insertConstIntInstruction(IRCode code, InternalOptions options, int value) {
+ throw new Unimplemented();
+ }
+
+ @Override
public void replaceCurrentInstructionWithThrowNull(
AppView<? extends AppInfoWithSubtyping> appView,
IRCode code,