Skip read-for-write instructions in is-field-read analysis
Bug: 149673849
Change-Id: I291205160a3baf258b3b0a2a223e348ea39575f9
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index ab9165b..2f90085 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -26,6 +26,8 @@
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
import com.android.tools.r8.cf.code.CfIinc;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
@@ -44,11 +46,14 @@
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -75,7 +80,6 @@
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
-import org.objectweb.asm.Opcodes;
/** Rudimentary printer to print the source representation for creating CfCode object. */
public class CfCodePrinter extends CfPrinter {
@@ -531,24 +535,28 @@
}
@Override
- public void print(CfFieldInstruction insn) {
- printNewInstruction(
- "CfFieldInstruction", fieldInstructionOpcode(insn), dexField(insn.getField()));
+ public void print(CfInstanceFieldRead insn) {
+ printNewInstruction("CfInstanceFieldRead", dexField(insn.getField()));
}
- private String fieldInstructionOpcode(CfFieldInstruction insn) {
- switch (insn.getOpcode()) {
- case Opcodes.GETSTATIC:
- return asmOpcodesType() + ".GETSTATIC";
- case Opcodes.PUTSTATIC:
- return asmOpcodesType() + ".PUTSTATIC";
- case Opcodes.GETFIELD:
- return asmOpcodesType() + ".GETFIELD";
- case Opcodes.PUTFIELD:
- return asmOpcodesType() + ".PUTFIELD";
- default:
- throw new Unimplemented();
- }
+ @Override
+ public void print(CfInstanceFieldWrite insn) {
+ printNewInstruction("CfInstanceFieldWrite", dexField(insn.getField()));
+ }
+
+ @Override
+ public void print(CfStaticFieldRead insn) {
+ printNewInstruction("CfStaticFieldRead", dexField(insn.getField()));
+ }
+
+ @Override
+ public void print(CfStaticFieldWrite insn) {
+ printNewInstruction("CfStaticFieldWrite", dexField(insn.getField()));
+ }
+
+ @Override
+ public void print(CfFieldInstruction insn) {
+ throw new Unreachable();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 3bdfcbf..d0a3c23 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -25,6 +25,8 @@
import com.android.tools.r8.cf.code.CfIfCmp;
import com.android.tools.r8.cf.code.CfIinc;
import com.android.tools.r8.cf.code.CfInitClass;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
@@ -46,6 +48,8 @@
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfSwitch.Kind;
@@ -472,6 +476,22 @@
appendClass(insn.getType());
}
+ public void print(CfInstanceFieldRead insn) {
+ print(insn.asFieldInstruction());
+ }
+
+ public void print(CfInstanceFieldWrite insn) {
+ print(insn.asFieldInstruction());
+ }
+
+ public void print(CfStaticFieldRead insn) {
+ print(insn.asFieldInstruction());
+ }
+
+ public void print(CfStaticFieldWrite insn) {
+ print(insn.asFieldInstruction());
+ }
+
public void print(CfFieldInstruction insn) {
indent();
switch (insn.getOpcode()) {
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 a2f4e80..2585329 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
@@ -10,14 +10,12 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
-import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
@@ -28,11 +26,10 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
-import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
-public class CfFieldInstruction extends CfInstruction {
+public abstract class CfFieldInstruction extends CfInstruction {
private final int opcode;
private final DexField field;
@@ -53,6 +50,21 @@
assert field.type == declaringField.type;
}
+ public static CfFieldInstruction create(int opcode, DexField field, DexField declaringField) {
+ switch (opcode) {
+ case Opcodes.GETSTATIC:
+ return new CfStaticFieldRead(field, declaringField);
+ case Opcodes.PUTSTATIC:
+ return new CfStaticFieldWrite(field, declaringField);
+ case Opcodes.GETFIELD:
+ return new CfInstanceFieldRead(field, declaringField);
+ case Opcodes.PUTFIELD:
+ return new CfInstanceFieldWrite(field, declaringField);
+ default:
+ throw new Unreachable("Unexpected opcode " + opcode);
+ }
+ }
+
public DexField getField() {
return field;
}
@@ -110,27 +122,6 @@
}
@Override
- void internalRegisterUse(
- UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
- switch (opcode) {
- case Opcodes.GETFIELD:
- registry.registerInstanceFieldRead(field);
- break;
- case Opcodes.PUTFIELD:
- registry.registerInstanceFieldWrite(field);
- break;
- case Opcodes.GETSTATIC:
- registry.registerStaticFieldRead(field);
- break;
- case Opcodes.PUTSTATIC:
- registry.registerStaticFieldWrite(field);
- break;
- default:
- throw new Unreachable("Unexpected opcode " + opcode);
- }
- }
-
- @Override
public boolean canThrow() {
return true;
}
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
new file mode 100644
index 0000000..145bc94
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.cf.code;
+
+import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.UseRegistry;
+import java.util.ListIterator;
+import org.objectweb.asm.Opcodes;
+
+public class CfInstanceFieldRead extends CfFieldInstruction implements CfOrDexInstanceFieldRead {
+
+ public CfInstanceFieldRead(DexField field) {
+ this(field, field);
+ }
+
+ public CfInstanceFieldRead(DexField field, DexField declaringField) {
+ super(Opcodes.GETFIELD, field, declaringField);
+ }
+
+ @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
new file mode 100644
index 0000000..6d01f49
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, 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.cf.code;
+
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.UseRegistry;
+import java.util.ListIterator;
+import org.objectweb.asm.Opcodes;
+
+public class CfInstanceFieldWrite extends CfFieldInstruction {
+
+ public CfInstanceFieldWrite(DexField field) {
+ this(field, field);
+ }
+
+ public CfInstanceFieldWrite(DexField field, DexField declaringField) {
+ super(Opcodes.PUTFIELD, field, declaringField);
+ }
+
+ @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/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 742a2be..4427f41 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
@@ -110,6 +111,11 @@
return true;
}
+ @Override
+ public Instruction asDexInstruction() {
+ return null;
+ }
+
public CfRecordFieldValues asRecordFieldValues() {
return null;
}
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
new file mode 100644
index 0000000..66fc48e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.cf.code;
+
+import com.android.tools.r8.code.CfOrDexStaticFieldRead;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.UseRegistry;
+import java.util.ListIterator;
+import org.objectweb.asm.Opcodes;
+
+public class CfStaticFieldRead extends CfFieldInstruction implements CfOrDexStaticFieldRead {
+
+ public CfStaticFieldRead(DexField field) {
+ super(Opcodes.GETSTATIC, field);
+ }
+
+ public CfStaticFieldRead(DexField field, DexField declaringField) {
+ super(Opcodes.GETSTATIC, field, declaringField);
+ }
+
+ @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
new file mode 100644
index 0000000..2cd0f26
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, 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.cf.code;
+
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.UseRegistry;
+import java.util.ListIterator;
+import org.objectweb.asm.Opcodes;
+
+public class CfStaticFieldWrite extends CfFieldInstruction {
+
+ public CfStaticFieldWrite(DexField field) {
+ super(Opcodes.PUTSTATIC, field);
+ }
+
+ public CfStaticFieldWrite(DexField field, DexField declaringField) {
+ super(Opcodes.PUTSTATIC, field, declaringField);
+ }
+
+ @Override
+ void internalRegisterUse(
+ UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
+ registry.registerStaticFieldWrite(getField());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexInstanceFieldRead.java b/src/main/java/com/android/tools/r8/code/CfOrDexInstanceFieldRead.java
new file mode 100644
index 0000000..3d560fc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/code/CfOrDexInstanceFieldRead.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, 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.code;
+
+import com.android.tools.r8.graph.DexField;
+
+public interface CfOrDexInstanceFieldRead extends CfOrDexInstruction {
+
+ DexField getField();
+}
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java b/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
index e85c75c..e8ac111 100644
--- a/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
+++ b/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
@@ -11,4 +11,6 @@
CfInstruction asCfInstruction();
boolean isCfInstruction();
+
+ Instruction asDexInstruction();
}
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexStaticFieldRead.java b/src/main/java/com/android/tools/r8/code/CfOrDexStaticFieldRead.java
new file mode 100644
index 0000000..121023a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/code/CfOrDexStaticFieldRead.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, 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.code;
+
+import com.android.tools.r8.graph.DexField;
+
+public interface CfOrDexStaticFieldRead extends CfOrDexInstruction {
+
+ DexField getField();
+}
diff --git a/src/main/java/com/android/tools/r8/code/Iget.java b/src/main/java/com/android/tools/r8/code/Iget.java
index 71c11c3..ee8e7a0 100644
--- a/src/main/java/com/android/tools/r8/code/Iget.java
+++ b/src/main/java/com/android/tools/r8/code/Iget.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class Iget extends IgetOrIput {
+public class Iget extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x52;
public static final String NAME = "Iget";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetBoolean.java b/src/main/java/com/android/tools/r8/code/IgetBoolean.java
index 36c00b6..3212878 100644
--- a/src/main/java/com/android/tools/r8/code/IgetBoolean.java
+++ b/src/main/java/com/android/tools/r8/code/IgetBoolean.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IgetBoolean extends IgetOrIput {
+public class IgetBoolean extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x55;
public static final String NAME = "IgetBoolean";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetByte.java b/src/main/java/com/android/tools/r8/code/IgetByte.java
index 8d57bb5..a876d70 100644
--- a/src/main/java/com/android/tools/r8/code/IgetByte.java
+++ b/src/main/java/com/android/tools/r8/code/IgetByte.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IgetByte extends IgetOrIput {
+public class IgetByte extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x56;
public static final String NAME = "IgetByte";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetChar.java b/src/main/java/com/android/tools/r8/code/IgetChar.java
index 2ba0e26..efa458d 100644
--- a/src/main/java/com/android/tools/r8/code/IgetChar.java
+++ b/src/main/java/com/android/tools/r8/code/IgetChar.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IgetChar extends IgetOrIput {
+public class IgetChar extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x57;
public static final String NAME = "IgetChar";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetObject.java b/src/main/java/com/android/tools/r8/code/IgetObject.java
index c685229..93540d6 100644
--- a/src/main/java/com/android/tools/r8/code/IgetObject.java
+++ b/src/main/java/com/android/tools/r8/code/IgetObject.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IgetObject extends IgetOrIput {
+public class IgetObject extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x54;
public static final String NAME = "IgetObject";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetShort.java b/src/main/java/com/android/tools/r8/code/IgetShort.java
index 77667ba..23bd792 100644
--- a/src/main/java/com/android/tools/r8/code/IgetShort.java
+++ b/src/main/java/com/android/tools/r8/code/IgetShort.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IgetShort extends IgetOrIput {
+public class IgetShort extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x58;
public static final String NAME = "IgetShort";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetWide.java b/src/main/java/com/android/tools/r8/code/IgetWide.java
index a71b95a..12ad976 100644
--- a/src/main/java/com/android/tools/r8/code/IgetWide.java
+++ b/src/main/java/com/android/tools/r8/code/IgetWide.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IgetWide extends IgetOrIput {
+public class IgetWide extends IgetOrIput implements CfOrDexInstanceFieldRead {
public static final int OPCODE = 0x53;
public static final String NAME = "IgetWide";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerInstanceFieldRead(getField());
+ registry.registerInstanceFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index 03d7a3d..1a594e9 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -151,6 +151,11 @@
return false;
}
+ @Override
+ public Instruction asDexInstruction() {
+ return this;
+ }
+
public CheckCast asCheckCast() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/code/Sget.java b/src/main/java/com/android/tools/r8/code/Sget.java
index c2d93df..2bd4653 100644
--- a/src/main/java/com/android/tools/r8/code/Sget.java
+++ b/src/main/java/com/android/tools/r8/code/Sget.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class Sget extends SgetOrSput {
+public class Sget extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x60;
public static final String NAME = "Sget";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SgetBoolean.java b/src/main/java/com/android/tools/r8/code/SgetBoolean.java
index 3d79934..fb51776 100644
--- a/src/main/java/com/android/tools/r8/code/SgetBoolean.java
+++ b/src/main/java/com/android/tools/r8/code/SgetBoolean.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SgetBoolean extends SgetOrSput {
+public class SgetBoolean extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x63;
public static final String NAME = "SgetBoolean";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SgetByte.java b/src/main/java/com/android/tools/r8/code/SgetByte.java
index 08f2b97..ee693ac 100644
--- a/src/main/java/com/android/tools/r8/code/SgetByte.java
+++ b/src/main/java/com/android/tools/r8/code/SgetByte.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SgetByte extends SgetOrSput {
+public class SgetByte extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x64;
public static final String NAME = "SgetByte";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SgetChar.java b/src/main/java/com/android/tools/r8/code/SgetChar.java
index 5ce7f8c..5f61f90 100644
--- a/src/main/java/com/android/tools/r8/code/SgetChar.java
+++ b/src/main/java/com/android/tools/r8/code/SgetChar.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SgetChar extends SgetOrSput {
+public class SgetChar extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x65;
public static final String NAME = "SgetChar";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SgetObject.java b/src/main/java/com/android/tools/r8/code/SgetObject.java
index e4ae240..8e5018e 100644
--- a/src/main/java/com/android/tools/r8/code/SgetObject.java
+++ b/src/main/java/com/android/tools/r8/code/SgetObject.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SgetObject extends SgetOrSput {
+public class SgetObject extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x62;
public static final String NAME = "SgetObject";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SgetShort.java b/src/main/java/com/android/tools/r8/code/SgetShort.java
index 62e2de7..99fc4ee 100644
--- a/src/main/java/com/android/tools/r8/code/SgetShort.java
+++ b/src/main/java/com/android/tools/r8/code/SgetShort.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SgetShort extends SgetOrSput {
+public class SgetShort extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x66;
public static final String NAME = "SgetShort";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SgetWide.java b/src/main/java/com/android/tools/r8/code/SgetWide.java
index 962d0c1..75a4343 100644
--- a/src/main/java/com/android/tools/r8/code/SgetWide.java
+++ b/src/main/java/com/android/tools/r8/code/SgetWide.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SgetWide extends SgetOrSput {
+public class SgetWide extends SgetOrSput implements CfOrDexStaticFieldRead {
public static final int OPCODE = 0x61;
public static final String NAME = "SgetWide";
@@ -39,7 +39,7 @@
@Override
public void registerUse(UseRegistry<?> registry) {
- registry.registerStaticFieldRead(getField());
+ registry.registerStaticFieldReadInstruction(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 205422c..0d6c31e 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
@@ -30,6 +32,10 @@
+ getClass().getCanonicalName());
}
+ public BytecodeInstructionMetadata getMetadata(CfOrDexInstruction instruction) {
+ return null;
+ }
+
public abstract void registerCodeReferences(ProgramMethod method, UseRegistry registry);
public abstract void registerCodeReferencesForDesugaring(
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 49d72ca..af3bcde 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
import com.android.tools.r8.code.SwitchPayload;
@@ -115,6 +116,11 @@
return this;
}
+ @Override
+ public BytecodeInstructionMetadata getMetadata(CfOrDexInstruction instruction) {
+ return getMetadata(instruction.asDexInstruction());
+ }
+
public BytecodeInstructionMetadata getMetadata(Instruction instruction) {
return metadata.getMetadata(instruction);
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index f111c9e..ba5faec 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -782,7 +782,7 @@
factory.createField(createTypeFromInternalType(owner), factory.createType(desc), name);
// TODO(mathiasr): Don't require CfFieldInstruction::declaringField. It is needed for proper
// renaming in the backend, but it is not available here in the frontend.
- instructions.add(new CfFieldInstruction(opcode, field, field));
+ instructions.add(CfFieldInstruction.create(opcode, field, field));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 4dd921c..8ac7c59 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -3,7 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.code.CfOrDexStaticFieldRead;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.utils.TraversalContinuation;
import java.util.ListIterator;
@@ -84,6 +86,10 @@
public abstract void registerInstanceFieldRead(DexField field);
+ public void registerInstanceFieldReadInstruction(CfOrDexInstanceFieldRead instruction) {
+ registerInstanceFieldRead(instruction.getField());
+ }
+
public void registerInstanceFieldReadFromMethodHandle(DexField field) {
registerInstanceFieldRead(field);
}
@@ -108,6 +114,10 @@
public abstract void registerStaticFieldRead(DexField field);
+ public void registerStaticFieldReadInstruction(CfOrDexStaticFieldRead instruction) {
+ registerStaticFieldRead(instruction.getField());
+ }
+
public void registerStaticFieldReadFromMethodHandle(DexField field) {
registerStaticFieldRead(field);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index 37e08d2..45bff3f 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfLogicalBinop;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -109,9 +110,9 @@
CfConstNumber.class,
CfGoto.class,
CfConstNumber.class,
- CfFieldInstruction.class);
+ CfStaticFieldWrite.class);
private static List<Class<?>> r8InstructionSequence =
- ImmutableList.of(CfConstNumber.class, CfLogicalBinop.class, CfFieldInstruction.class);
+ ImmutableList.of(CfConstNumber.class, CfLogicalBinop.class, CfStaticFieldWrite.class);
private static List<Class<?>> jacocoInstructionSequence =
ImmutableList.of(CfLoad.class, CfConstNumber.class, CfConstNumber.class, CfArrayStore.class);
diff --git a/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeInstructionMetadata.java b/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeInstructionMetadata.java
index 8935c35..97839cf 100644
--- a/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeInstructionMetadata.java
+++ b/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeInstructionMetadata.java
@@ -10,14 +10,47 @@
*/
public class BytecodeInstructionMetadata {
+ /**
+ * Set for instance and static field read instructions which are only used to write the same
+ * field.
+ *
+ * <p>Used by {@link com.android.tools.r8.ir.analysis.fieldaccess.TrivialFieldAccessReprocessor}
+ * to skip such instructions in the "is-field-read" analysis.
+ */
+ private final boolean isReadForWrite;
+
+ BytecodeInstructionMetadata(boolean isReadForWrite) {
+ this.isReadForWrite = isReadForWrite;
+ }
+
public static Builder builder() {
return new Builder();
}
+ public static BytecodeInstructionMetadata none() {
+ return null;
+ }
+
+ public boolean isReadForWrite() {
+ return isReadForWrite;
+ }
+
public static class Builder {
+ private boolean isReadForWrite;
+
+ private boolean isEmpty() {
+ return !isReadForWrite;
+ }
+
+ public Builder setIsReadForWrite() {
+ isReadForWrite = true;
+ return this;
+ }
+
public BytecodeInstructionMetadata build() {
- return new BytecodeInstructionMetadata();
+ assert !isEmpty();
+ return new BytecodeInstructionMetadata(isReadForWrite);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadata.java b/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadata.java
index c1923b3..ad7dee4 100644
--- a/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadata.java
+++ b/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadata.java
@@ -8,6 +8,7 @@
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.Objects;
/**
* A collection of information that pertains to the instructions in a piece of {@link
@@ -20,6 +21,7 @@
private final Map<I, BytecodeInstructionMetadata> backing;
BytecodeMetadata(Map<I, BytecodeInstructionMetadata> backing) {
+ assert backing.values().stream().noneMatch(Objects::isNull);
this.backing = backing;
}
diff --git a/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadataProvider.java b/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadataProvider.java
index f255c74..02ba8d4 100644
--- a/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadataProvider.java
+++ b/src/main/java/com/android/tools/r8/graph/bytecodemetadata/BytecodeMetadataProvider.java
@@ -67,7 +67,7 @@
}
Map<Instruction, BytecodeInstructionMetadata> backing =
new IdentityHashMap<>(builders.size());
- builders.forEach(((instruction, builder) -> backing.put(instruction, builder.build())));
+ builders.forEach((instruction, builder) -> backing.put(instruction, builder.build()));
return new BytecodeMetadataProvider(backing);
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
index 66251ba..2affeaf 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfDexItemBasedConstString;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
@@ -129,7 +129,7 @@
int classIdLocalIndex = maxLocals - 1;
instructionBuilder.add(new CfLoad(ValueType.OBJECT, 0));
instructionBuilder.add(new CfLoad(ValueType.INT, classIdLocalIndex));
- instructionBuilder.add(new CfFieldInstruction(Opcodes.PUTFIELD, group.getClassIdField()));
+ instructionBuilder.add(new CfInstanceFieldWrite(group.getClassIdField()));
maxStack.set(2);
} else {
assert !hasClassId;
@@ -187,7 +187,7 @@
int stackSizeForInitializationInfo =
addCfInstructionsForInitializationInfo(
instructionBuilder, initializationInfo, argumentToLocalIndex, field.getType());
- instructionBuilder.add(new CfFieldInstruction(Opcodes.PUTFIELD, field));
+ instructionBuilder.add(new CfInstanceFieldWrite(field));
maxStack.setMax(stackSizeForInitializationInfo + 1);
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java
index 93a8c71..3b4f8dc 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java
@@ -5,10 +5,17 @@
package com.android.tools.r8.ir.analysis.fieldaccess;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata.Builder;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.FieldGet;
import com.android.tools.r8.ir.code.FieldInstruction;
+import com.android.tools.r8.ir.code.FieldPut;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.WorkList;
public class FieldReadForWriteAnalysis {
@@ -22,6 +29,53 @@
FieldInstruction instruction,
ProgramField field,
BytecodeMetadataProvider.Builder bytecodeMetadataProviderBuilder) {
- // TODO(b/149673849): Determine if field read is only used for field write.
+ if (instruction.isFieldPut()) {
+ return;
+ }
+
+ FieldGet fieldGet = instruction.asFieldGet();
+ if (isValueOnlyUsedToWriteField(fieldGet.outValue(), field)) {
+ bytecodeMetadataProviderBuilder.addMetadata(instruction, Builder::setIsReadForWrite);
+ }
+ }
+
+ private boolean isValueOnlyUsedToWriteField(Value value, ProgramField field) {
+ WorkList<Instruction> users = WorkList.newIdentityWorkList(value.uniqueUsers());
+ if (!enqueueUsersForAnalysis(value, users)) {
+ return false;
+ }
+ boolean foundWrite = false;
+ while (users.hasNext()) {
+ Instruction user = users.next();
+ if (user.isArithmeticBinop() || user.isLogicalBinop() || user.isUnop()) {
+ if (enqueueUsersForAnalysis(user.outValue(), users)) {
+ // OK.
+ continue;
+ }
+ } else if (user.isFieldPut()) {
+ FieldPut fieldPut = user.asFieldPut();
+ DexField writtenFieldReference = fieldPut.getField();
+ if (writtenFieldReference.match(field.getReference())
+ && fieldPut.isStaticPut() == field.getAccessFlags().isStatic()) {
+ ProgramField writtenField =
+ appView.appInfo().resolveField(writtenFieldReference).getProgramField();
+ if (writtenField != null && writtenField.isStructurallyEqualTo(field)) {
+ // OK.
+ foundWrite = true;
+ continue;
+ }
+ }
+ }
+ return false;
+ }
+ return foundWrite;
+ }
+
+ private boolean enqueueUsersForAnalysis(Value value, WorkList<Instruction> users) {
+ if (value.hasDebugUsers() || value.hasPhiUsers()) {
+ return false;
+ }
+ users.addIfNotSeen(value.uniqueUsers());
+ return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index 7e6d5d3..f392dec 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -4,6 +4,10 @@
package com.android.tools.r8.ir.analysis.fieldaccess;
+import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
+
+import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
+import com.android.tools.r8.code.CfOrDexStaticFieldRead;
import com.android.tools.r8.graph.AbstractAccessContexts;
import com.android.tools.r8.graph.AbstractAccessContexts.ConcreteAccessContexts;
import com.android.tools.r8.graph.AppView;
@@ -19,6 +23,7 @@
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.ReferenceTypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -26,7 +31,6 @@
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
@@ -95,7 +99,14 @@
constantFields.forEach(this::markFieldAsDead);
readFields.keySet().forEach(this::markFieldAsDead);
- writtenFields.keySet().forEach(this::markFieldAsDead);
+ writtenFields.keySet().forEach(this::markWriteOnlyFieldAsDead);
+ }
+
+ private void markWriteOnlyFieldAsDead(DexEncodedField field) {
+ markFieldAsDead(field);
+ getSimpleFeedback()
+ .recordFieldHasAbstractValue(
+ field, appView, appView.abstractValueFactory().createNullValue());
}
private void markFieldAsDead(DexEncodedField field) {
@@ -104,7 +115,7 @@
if (appView.appInfo().isPinned(field)) {
assert field.getType().isAlwaysNull(appView);
} else {
- OptimizationFeedbackSimple.getInstance().markFieldAsDead(field);
+ getSimpleFeedback().markFieldAsDead(field);
}
}
@@ -294,7 +305,11 @@
super(appView, method);
}
- private void registerFieldAccess(DexField reference, boolean isStatic, boolean isWrite) {
+ private void registerFieldAccess(
+ DexField reference,
+ boolean isStatic,
+ boolean isWrite,
+ BytecodeInstructionMetadata metadata) {
SuccessfulFieldResolutionResult resolutionResult =
appView.appInfo().resolveField(reference).asSuccessfulResolution();
if (resolutionResult == null) {
@@ -311,6 +326,13 @@
return;
}
+ if (metadata != null && metadata.isReadForWrite()) {
+ // Ignore this read. If the field ends up only being written, then we will still reprocess
+ // the method with the read-for-write instruction, since the method contains a write that
+ // requires reprocessing.
+ return;
+ }
+
// Record access.
if (field.isProgramField() && appView.appInfo().mayPropagateValueFor(field)) {
if (field.getAccessFlags().isStatic() == isStatic) {
@@ -372,22 +394,36 @@
@Override
public void registerInstanceFieldRead(DexField field) {
- registerFieldAccess(field, false, false);
+ registerFieldAccess(field, false, false, BytecodeInstructionMetadata.none());
+ }
+
+ @Override
+ public void registerInstanceFieldReadInstruction(CfOrDexInstanceFieldRead instruction) {
+ BytecodeInstructionMetadata metadata =
+ getContext().getDefinition().getCode().getMetadata(instruction);
+ registerFieldAccess(instruction.getField(), false, false, metadata);
}
@Override
public void registerInstanceFieldWrite(DexField field) {
- registerFieldAccess(field, false, true);
+ registerFieldAccess(field, false, true, null);
}
@Override
public void registerStaticFieldRead(DexField field) {
- registerFieldAccess(field, true, false);
+ registerFieldAccess(field, true, false, BytecodeInstructionMetadata.none());
+ }
+
+ @Override
+ public void registerStaticFieldReadInstruction(CfOrDexStaticFieldRead instruction) {
+ BytecodeInstructionMetadata metadata =
+ getContext().getDefinition().getCode().getMetadata(instruction);
+ registerFieldAccess(instruction.getField(), true, false, metadata);
}
@Override
public void registerStaticFieldWrite(DexField field) {
- registerFieldAccess(field, true, true);
+ registerFieldAccess(field, true, true, null);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldGet.java b/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
new file mode 100644
index 0000000..3f62f1f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, 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.code;
+
+public interface FieldGet {
+
+ Value outValue();
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index 090812b..347ca58 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.cf.LoadStoreHelper;
import com.android.tools.r8.cf.TypeVerificationHelper;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
import com.android.tools.r8.code.Iget;
import com.android.tools.r8.code.IgetBoolean;
import com.android.tools.r8.code.IgetByte;
@@ -32,7 +32,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Set;
-public class InstanceGet extends FieldInstruction implements InstanceFieldInstruction {
+public class InstanceGet extends FieldInstruction implements FieldGet, InstanceFieldInstruction {
public InstanceGet(Value dest, Value object, DexField field) {
super(field, dest, object);
@@ -148,6 +148,16 @@
}
@Override
+ public boolean isFieldGet() {
+ return true;
+ }
+
+ @Override
+ public FieldGet asFieldGet() {
+ return this;
+ }
+
+ @Override
public boolean isInstanceFieldInstruction() {
return true;
}
@@ -190,9 +200,7 @@
@Override
public void buildCf(CfBuilder builder) {
- builder.add(
- new CfFieldInstruction(
- org.objectweb.asm.Opcodes.GETFIELD, getField(), builder.resolveField(getField())));
+ builder.add(new CfInstanceFieldRead(getField(), builder.resolveField(getField())));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 3dff277..2a5d60e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.cf.LoadStoreHelper;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.code.Iput;
import com.android.tools.r8.code.IputBoolean;
import com.android.tools.r8.code.IputByte;
@@ -195,6 +195,16 @@
}
@Override
+ public boolean isFieldPut() {
+ return true;
+ }
+
+ @Override
+ public FieldPut asFieldPut() {
+ return this;
+ }
+
+ @Override
public boolean isInstanceFieldInstruction() {
return true;
}
@@ -226,9 +236,7 @@
@Override
public void buildCf(CfBuilder builder) {
- builder.add(
- new CfFieldInstruction(
- org.objectweb.asm.Opcodes.PUTFIELD, getField(), builder.resolveField(getField())));
+ builder.add(new CfInstanceFieldWrite(getField(), builder.resolveField(getField())));
}
@Override
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 090fb45..3409c01 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
@@ -956,12 +956,20 @@
return null;
}
- public final boolean isFieldGet() {
- return isInstanceGet() || isStaticGet();
+ public boolean isFieldGet() {
+ return false;
}
- public final boolean isFieldPut() {
- return isInstancePut() || isStaticPut();
+ public FieldGet asFieldGet() {
+ return null;
+ }
+
+ public boolean isFieldPut() {
+ return false;
+ }
+
+ public FieldPut asFieldPut() {
+ return null;
}
public boolean isInstancePut() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index b4caedd..c7e076c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.cf.LoadStoreHelper;
import com.android.tools.r8.cf.TypeVerificationHelper;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.code.Sget;
import com.android.tools.r8.code.SgetBoolean;
import com.android.tools.r8.code.SgetByte;
@@ -32,7 +32,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Set;
-public class StaticGet extends FieldInstruction implements StaticFieldInstruction {
+public class StaticGet extends FieldInstruction implements FieldGet, StaticFieldInstruction {
public StaticGet(Value dest, DexField field) {
super(field, dest, (Value) null);
@@ -183,6 +183,16 @@
}
@Override
+ public boolean isFieldGet() {
+ return true;
+ }
+
+ @Override
+ public FieldGet asFieldGet() {
+ return this;
+ }
+
+ @Override
public boolean isStaticFieldInstruction() {
return true;
}
@@ -204,9 +214,7 @@
@Override
public void buildCf(CfBuilder builder) {
- builder.add(
- new CfFieldInstruction(
- org.objectweb.asm.Opcodes.GETSTATIC, getField(), builder.resolveField(getField())));
+ builder.add(new CfStaticFieldRead(getField(), builder.resolveField(getField())));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index 92eea52..8cbeb6d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.cf.LoadStoreHelper;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.code.Sput;
import com.android.tools.r8.code.SputBoolean;
import com.android.tools.r8.code.SputByte;
@@ -185,6 +185,16 @@
}
@Override
+ public boolean isFieldPut() {
+ return true;
+ }
+
+ @Override
+ public FieldPut asFieldPut() {
+ return this;
+ }
+
+ @Override
public boolean isStaticFieldInstruction() {
return true;
}
@@ -206,9 +216,7 @@
@Override
public void buildCf(CfBuilder builder) {
- builder.add(
- new CfFieldInstruction(
- org.objectweb.asm.Opcodes.PUTSTATIC, getField(), builder.resolveField(getField())));
+ builder.add(new CfStaticFieldWrite(getField(), builder.resolveField(getField())));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
index fd7a8b9..b0abf2a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
@@ -4,12 +4,12 @@
package com.android.tools.r8.ir.desugar;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfNew;
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.graph.CfCode;
import com.google.common.collect.ImmutableList;
import org.objectweb.asm.Opcodes;
@@ -29,7 +29,7 @@
new CfNew(lambda.type),
new CfStackInstruction(Opcode.Dup),
new CfInvoke(Opcodes.INVOKESPECIAL, lambda.constructor, false),
- new CfFieldInstruction(Opcodes.PUTSTATIC, lambda.lambdaField, lambda.lambdaField),
+ new CfStaticFieldWrite(lambda.lambdaField, lambda.lambdaField),
new CfReturnVoid()),
ImmutableList.of(),
ImmutableList.of());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
index 65ead77..7ccba56 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.desugar;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLoad;
@@ -42,7 +42,7 @@
ValueType type = ValueType.fromDexType(field.type);
instructions.add(new CfLoad(ValueType.OBJECT, 0));
instructions.add(new CfLoad(type, maxLocals));
- instructions.add(new CfFieldInstruction(Opcodes.PUTFIELD, field, field));
+ instructions.add(new CfInstanceFieldWrite(field));
maxLocals += type.requiredRegisters();
maxStack += type.requiredRegisters();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index acfee7b..eb5a2eb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.cf.code.CfCheckCast;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLoad;
@@ -233,7 +233,7 @@
DexField field = lambda.getCaptureField(i);
ValueType valueType = ValueType.fromDexType(field.type);
instructions.add(new CfLoad(ValueType.OBJECT, 0));
- instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, field, field));
+ instructions.add(new CfInstanceFieldRead(field));
maxStack += valueType.requiredRegisters();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index 3d7ae96..3f9e078 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -7,9 +7,7 @@
import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.THROW_ICCE;
import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.THROW_NSME;
import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
-import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
-import static org.objectweb.asm.Opcodes.PUTSTATIC;
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfConstClass;
@@ -17,7 +15,6 @@
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
@@ -30,6 +27,8 @@
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
@@ -242,7 +241,7 @@
CfLabel tryCatchTarget = new CfLabel();
CfLabel tryCatchEndFinally = new CfLabel();
- instructions.add(new CfFieldInstruction(GETSTATIC, initializedValueField));
+ instructions.add(new CfStaticFieldRead(initializedValueField));
instructions.add(new CfIf(If.Type.NE, ValueType.INT, initializedTrue));
instructions.add(new CfConstClass(builder.getType()));
@@ -251,13 +250,13 @@
instructions.add(new CfMonitor(Monitor.Type.ENTER));
instructions.add(tryCatchStart);
- instructions.add(new CfFieldInstruction(GETSTATIC, initializedValueField));
+ instructions.add(new CfStaticFieldRead(initializedValueField));
instructions.add(new CfIf(If.Type.NE, ValueType.INT, initializedTrueSecond));
invokeBootstrapMethod(instructions);
- instructions.add(new CfFieldInstruction(PUTSTATIC, constantValueField));
+ instructions.add(new CfStaticFieldWrite(constantValueField));
instructions.add(new CfConstNumber(1, ValueType.INT));
- instructions.add(new CfFieldInstruction(PUTSTATIC, initializedValueField));
+ instructions.add(new CfStaticFieldWrite(initializedValueField));
instructions.add(initializedTrueSecond);
instructions.add(
@@ -287,7 +286,7 @@
instructions.add(initializedTrue);
instructions.add(new CfFrame(ImmutableInt2ReferenceSortedMap.empty(), ImmutableDeque.of()));
- instructions.add(new CfFieldInstruction(GETSTATIC, constantValueField));
+ instructions.add(new CfStaticFieldRead(constantValueField));
instructions.add(new CfReturn(ValueType.OBJECT));
List<CfTryCatch> tryCatchRanges =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 6b76836..7226037 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -6,11 +6,11 @@
import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInitClass;
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -44,7 +44,6 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
-import org.objectweb.asm.Opcodes;
public class InterfaceDesugaringSyntheticHelper {
@@ -493,10 +492,7 @@
isWide ? 2 : 1,
0,
ImmutableList.of(
- new CfFieldInstruction(
- Opcodes.GETSTATIC,
- clinitField.getReference(),
- clinitField.getReference()),
+ new CfStaticFieldRead(clinitField.getReference(), clinitField.getReference()),
isWide
? new CfStackInstruction(Opcode.Pop2)
: new CfStackInstruction(Opcode.Pop),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
index 206c276..4c45086 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.desugar.lambda;
-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.cf.code.CfInvokeDynamic;
@@ -12,6 +11,7 @@
import com.android.tools.r8.cf.code.CfNew;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
@@ -123,8 +123,7 @@
if (lambdaClass.isStateless()) {
return ImmutableList.of(
- new CfFieldInstruction(
- Opcodes.GETSTATIC, lambdaClass.lambdaField, lambdaClass.lambdaField));
+ new CfStaticFieldRead(lambdaClass.lambdaField, lambdaClass.lambdaField));
}
DexTypeList captureTypes = lambdaClass.descriptor.captures;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 10ea774..90d49ac 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.cf.code.CfArrayStore;
import com.android.tools.r8.cf.code.CfConstNumber;
-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.cf.code.CfLoad;
@@ -18,6 +17,8 @@
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -267,7 +268,7 @@
instructions.add(new CfConstNumber(i + 1, ValueType.INT));
instructions.add(new CfArrayStore(MemberType.INT));
}
- instructions.add(new CfFieldInstruction(Opcodes.PUTSTATIC, valuesField.getReference()));
+ instructions.add(new CfStaticFieldWrite(valuesField.getReference()));
instructions.add(new CfReturnVoid());
int maxStack = 4;
@@ -317,7 +318,7 @@
new CfNewArray(dexItemFactory.intArrayType),
new CfStore(ValueType.OBJECT, resultLocalSlot),
// System.arraycopy(SharedUtilityClass.$VALUES, 0, result, 0, size);
- new CfFieldInstruction(Opcodes.GETSTATIC, valuesField.getReference()),
+ new CfStaticFieldRead(valuesField.getReference()),
new CfConstNumber(0, ValueType.INT),
new CfLoad(ValueType.OBJECT, resultLocalSlot),
new CfConstNumber(0, ValueType.INT),
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 7395cbf..6777d57 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -7,10 +7,11 @@
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfConstString;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
@@ -80,7 +81,7 @@
// use vivifiedTypes.
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
- instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, wrapperField, wrapperField));
+ instructions.add(new CfInstanceFieldRead(wrapperField));
int index = 1;
int stackIndex = 1;
DexType[] newParameters = forwardMethod.proto.parameters.values.clone();
@@ -250,7 +251,7 @@
@Override
void generatePushReceiver(List<CfInstruction> instructions) {
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
- instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, wrapperField, wrapperField));
+ instructions.add(new CfInstanceFieldRead(wrapperField));
}
@Override
@@ -299,8 +300,7 @@
instructions.add(new CfIf(If.Type.EQ, ValueType.INT, unwrapDest));
instructions.add(new CfLoad(ValueType.fromDexType(argType), 0));
instructions.add(new CfCheckCast(reverseWrapperField.holder));
- instructions.add(
- new CfFieldInstruction(Opcodes.GETFIELD, reverseWrapperField, reverseWrapperField));
+ instructions.add(new CfInstanceFieldRead(reverseWrapperField));
instructions.add(new CfReturn(ValueType.fromDexType(reverseWrapperField.type)));
instructions.add(unwrapDest);
instructions.add(new CfFrame(locals, ImmutableDeque.of()));
@@ -410,7 +410,7 @@
false));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.type), 1));
- instructions.add(new CfFieldInstruction(Opcodes.PUTFIELD, wrapperField, wrapperField));
+ instructions.add(new CfInstanceFieldWrite(wrapperField));
instructions.add(new CfReturnVoid());
return standardCfCodeFromInstructions(instructions);
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index cb5de3e..5ef065a 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
@@ -20,6 +19,8 @@
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
@@ -241,17 +242,17 @@
// return VALUES$com$x$MyEnum;
List<CfInstruction> instructions = new ArrayList<>();
CfLabel nullDest = new CfLabel();
- instructions.add(new CfFieldInstruction(Opcodes.GETSTATIC, utilityField, utilityField));
+ instructions.add(new CfStaticFieldRead(utilityField, utilityField));
instructions.add(new CfIf(If.Type.NE, ValueType.OBJECT, nullDest));
instructions.add((new CfConstNumber(numEnumInstances, ValueType.INT)));
assert initializationMethod.getArity() == 1;
instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, initializationMethod, false));
- instructions.add(new CfFieldInstruction(Opcodes.PUTSTATIC, utilityField, utilityField));
+ instructions.add(new CfStaticFieldWrite(utilityField, utilityField));
instructions.add(nullDest);
instructions.add(
new CfFrame(
ImmutableInt2ReferenceSortedMap.<FrameType>builder().build(), ImmutableDeque.of()));
- instructions.add(new CfFieldInstruction(Opcodes.GETSTATIC, utilityField, utilityField));
+ instructions.add(new CfStaticFieldRead(utilityField, utilityField));
instructions.add(new CfReturn(ValueType.OBJECT));
return standardCfCodeFromInstructions(instructions);
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java b/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
index d6794c6..f549990 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
@@ -103,7 +103,7 @@
// Get or set the field.
int opcode =
Opcodes.GETSTATIC + BooleanUtils.intValue(isSetter()) + (isInstanceField.ordinal() << 1);
- instructions.add(new CfFieldInstruction(opcode, field, field));
+ instructions.add(CfFieldInstruction.create(opcode, field, field));
// Return.
if (isSetter()) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
index 46124b9..be34a74 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
@@ -7,10 +7,10 @@
import com.android.tools.r8.cf.code.CfArrayStore;
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfConstNumber;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIfCmp;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
@@ -118,7 +118,7 @@
private void loadFieldAsObject(List<CfInstruction> instructions, DexField field) {
DexItemFactory factory = appView.dexItemFactory();
instructions.add(new CfLoad(ValueType.OBJECT, 0));
- instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, field, field));
+ instructions.add(new CfInstanceFieldRead(field));
if (field.type.isPrimitiveType()) {
factory.primitiveToBoxed.forEach(
(primitiveType, boxedType) -> {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldReadForWriteTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldReadForWriteTest.java
new file mode 100644
index 0000000..0c4e336
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldReadForWriteTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2021, 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.optimize.membervaluepropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ir.optimize.membervaluepropagation.FieldReadForWriteTest.R.anim;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FieldReadForWriteTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addHorizontallyMergedClassesInspector(
+ HorizontallyMergedClassesInspector::assertNoClassesMerged)
+ .enableNoHorizontalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject animClassSubject = inspector.clazz(anim.class);
+ if (parameters.isCfRuntime()) {
+ assertThat(animClassSubject, isPresent());
+ assertThat(animClassSubject.uniqueFieldWithName("abc_fade_in"), isPresent());
+ } else {
+ assertThat(animClassSubject, isAbsent());
+ }
+ });
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ int packageId = args.length;
+ R.onResourcesLoaded(packageId);
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class R {
+
+ static boolean sResourcesDidLoad;
+
+ @NoHorizontalClassMerging
+ static class anim {
+ public static int abc_fade_in = 0x7f010039;
+ }
+
+ static void onResourcesLoaded(int packageId) {
+ if (sResourcesDidLoad) {
+ return;
+ }
+ sResourcesDidLoad = true;
+ int packageIdTransform = (packageId ^ 0x7f) << 24;
+ onResourcesLoadedAnim(packageIdTransform);
+ }
+
+ static void onResourcesLoadedAnim(int packageIdTransform) {
+ // Arithmethic binop (add, div, mul, rem, sub).
+ anim.abc_fade_in += packageIdTransform;
+ anim.abc_fade_in /= packageIdTransform;
+ anim.abc_fade_in *= packageIdTransform;
+ anim.abc_fade_in %= packageIdTransform;
+ anim.abc_fade_in -= packageIdTransform;
+ // Logical binop (and, or, shl, shr, ush, xor).
+ anim.abc_fade_in &= packageIdTransform;
+ anim.abc_fade_in |= packageIdTransform;
+ anim.abc_fade_in <<= packageIdTransform;
+ anim.abc_fade_in >>= packageIdTransform;
+ anim.abc_fade_in >>>= packageIdTransform;
+ anim.abc_fade_in ^= packageIdTransform;
+ // Unop (number conversion, but also: inc, neg, not).
+ anim.abc_fade_in = (int) ((long) anim.abc_fade_in);
+ }
+ }
+}