R8 Assistant: Add AtomicUpdater support
Change-Id: I9deadcbf3155386059a5013bebf5a16e44035aa0
diff --git a/src/assistant/java/com/android/tools/r8/assistant/runtime/EmptyReflectiveOperationReceiver.java b/src/assistant/java/com/android/tools/r8/assistant/runtime/EmptyReflectiveOperationReceiver.java
index 6f874f5..0aa1326 100644
--- a/src/assistant/java/com/android/tools/r8/assistant/runtime/EmptyReflectiveOperationReceiver.java
+++ b/src/assistant/java/com/android/tools/r8/assistant/runtime/EmptyReflectiveOperationReceiver.java
@@ -53,4 +53,14 @@
@Override
public void onClassFlag(Stack stack, Class<?> clazz, ClassFlag classFlag) {}
+
+ @Override
+ public void onAtomicIntegerFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name) {}
+
+ @Override
+ public void onAtomicLongFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name) {}
+
+ @Override
+ public void onAtomicReferenceFieldUpdaterNewUpdater(
+ Stack stack, Class<?> clazz, Class<?> fieldClass, String name) {}
}
diff --git a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationLogger.java b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationLogger.java
index 76684c7..5df728a 100644
--- a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationLogger.java
+++ b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationLogger.java
@@ -83,6 +83,30 @@
System.out.println("Reflectively got class flag " + classFlag);
}
+ @Override
+ public void onAtomicIntegerFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name) {
+ System.out.println(
+ "Reflectively got AtomicIntegerFieldUpdater.newUpdater on " + clazz + "#" + name);
+ }
+
+ @Override
+ public void onAtomicLongFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name) {
+ System.out.println(
+ "Reflectively got AtomicLongFieldUpdater.newUpdater on " + clazz + "#" + name);
+ }
+
+ @Override
+ public void onAtomicReferenceFieldUpdaterNewUpdater(
+ Stack stack, Class<?> clazz, Class<?> fieldClass, String name) {
+ System.out.println(
+ "Reflectively got AtomicReferenceFieldUpdater.newUpdater on "
+ + fieldClass
+ + " "
+ + clazz
+ + "#"
+ + name);
+ }
+
public boolean requiresStackInformation() {
return true;
}
diff --git a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationReceiver.java b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationReceiver.java
index d4c43b8..79ff0e5 100644
--- a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationReceiver.java
+++ b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationReceiver.java
@@ -41,6 +41,13 @@
void onClassIsAssignableFrom(Stack stack, Class<?> clazz, Class<?> sup);
+ void onAtomicIntegerFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name);
+
+ void onAtomicLongFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name);
+
+ void onAtomicReferenceFieldUpdaterNewUpdater(
+ Stack stack, Class<?> clazz, Class<?> fieldClass, String name);
+
@KeepForApi
enum ClassFlag {
ANNOTATION,
diff --git a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOracle.java b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOracle.java
index 3188493..54d0eb9 100644
--- a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOracle.java
+++ b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOracle.java
@@ -182,4 +182,18 @@
public static void onClassGetField(Class<?> clazz, String name) {
getInstance().onClassGetField(Stack.createStack(), clazz, name);
}
+
+ public static void onAtomicIntegerFieldUpdaterNewUpdater(Class<?> clazz, String name) {
+ getInstance().onAtomicIntegerFieldUpdaterNewUpdater(Stack.createStack(), clazz, name);
+ }
+
+ public static void onAtomicLongFieldUpdaterNewUpdater(Class<?> clazz, String name) {
+ getInstance().onAtomicLongFieldUpdaterNewUpdater(Stack.createStack(), clazz, name);
+ }
+
+ public static void onAtomicReferenceFieldUpdaterNewUpdater(
+ Class<?> clazz, Class<?> fieldClass, String name) {
+ getInstance()
+ .onAtomicReferenceFieldUpdaterNewUpdater(Stack.createStack(), clazz, fieldClass, name);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/assistant/InstrumentedReflectiveMethodList.java b/src/main/java/com/android/tools/r8/assistant/InstrumentedReflectiveMethodList.java
index 9b9203a..928982f 100644
--- a/src/main/java/com/android/tools/r8/assistant/InstrumentedReflectiveMethodList.java
+++ b/src/main/java/com/android/tools/r8/assistant/InstrumentedReflectiveMethodList.java
@@ -130,6 +130,20 @@
"getMethods"),
getMethodReferenceWithClassParameter("onClassGetMethods"));
+ builder.put(
+ factory.atomicFieldUpdaterMethods.intUpdater,
+ getMethodReferenceWithClassAndStringParameter("onAtomicIntegerFieldUpdaterNewUpdater"));
+ builder.put(
+ factory.atomicFieldUpdaterMethods.longUpdater,
+ getMethodReferenceWithClassAndStringParameter("onAtomicLongFieldUpdaterNewUpdater"));
+ builder.put(
+ factory.atomicFieldUpdaterMethods.referenceUpdater,
+ getMethodReferenceWithParameterTypes(
+ "onAtomicReferenceFieldUpdaterNewUpdater",
+ factory.classType,
+ factory.classType,
+ factory.stringType));
+
return builder.build();
}
diff --git a/src/test/java/com/android/tools/r8/assistant/AtomicUpdaterTest.java b/src/test/java/com/android/tools/r8/assistant/AtomicUpdaterTest.java
new file mode 100644
index 0000000..360ea26
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/assistant/AtomicUpdaterTest.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2025, 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.assistant;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.assistant.JavaLangClassTestClass.Bar;
+import com.android.tools.r8.assistant.JavaLangClassTestClass.Foo;
+import com.android.tools.r8.assistant.runtime.EmptyReflectiveOperationReceiver;
+import com.android.tools.r8.assistant.runtime.ReflectiveOracle.Stack;
+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 AtomicUpdaterTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNativeMultidexDexRuntimes().withMaximumApiLevel().build();
+ }
+
+ @Test
+ public void testInstrumentationWithCustomOracle() throws Exception {
+ testForAssistant()
+ .addProgramClasses(AtomicUpdaterTestClass.class, Foo.class, Bar.class)
+ .addInstrumentationClasses(Instrumentation.class)
+ .setCustomReflectiveOperationReceiver(Instrumentation.class)
+ .setMinApi(parameters)
+ .compile()
+ .run(parameters.getRuntime(), AtomicUpdaterTestClass.class)
+ .assertSuccessWithOutputLines(
+ "int com.android.tools.r8.assistant.AtomicUpdaterTestClass#i",
+ "42",
+ "long com.android.tools.r8.assistant.AtomicUpdaterTestClass#l",
+ "42",
+ "java.lang.Object com.android.tools.r8.assistant.AtomicUpdaterTestClass#o",
+ "42");
+ }
+
+ public static class Instrumentation extends EmptyReflectiveOperationReceiver {
+
+ @Override
+ public void onAtomicIntegerFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name) {
+ System.out.println("int " + clazz.getName() + "#" + name);
+ }
+
+ @Override
+ public void onAtomicLongFieldUpdaterNewUpdater(Stack stack, Class<?> clazz, String name) {
+ System.out.println("long " + clazz.getName() + "#" + name);
+ }
+
+ @Override
+ public void onAtomicReferenceFieldUpdaterNewUpdater(
+ Stack stack, Class<?> clazz, Class<?> fieldClass, String name) {
+ System.out.println(fieldClass.getName() + " " + clazz.getName() + "#" + name);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/assistant/AtomicUpdaterTestClass.java b/src/test/java/com/android/tools/r8/assistant/AtomicUpdaterTestClass.java
new file mode 100644
index 0000000..adc0c22
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/assistant/AtomicUpdaterTestClass.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2025, 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.assistant;
+
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+public class AtomicUpdaterTestClass {
+
+ volatile int i;
+ volatile long l;
+ volatile Object o;
+
+ public static void main(String[] args) {
+ AtomicUpdaterTestClass inst = new AtomicUpdaterTestClass();
+
+ AtomicIntegerFieldUpdater<AtomicUpdaterTestClass> intUpdater =
+ AtomicIntegerFieldUpdater.newUpdater(AtomicUpdaterTestClass.class, "i");
+ intUpdater.set(inst, 42);
+ System.out.println(inst.i);
+
+ AtomicLongFieldUpdater<AtomicUpdaterTestClass> longUpdater =
+ AtomicLongFieldUpdater.newUpdater(AtomicUpdaterTestClass.class, "l");
+ longUpdater.set(inst, 42L);
+ System.out.println(inst.l);
+
+ AtomicReferenceFieldUpdater<AtomicUpdaterTestClass, Object> referenceUpdater =
+ AtomicReferenceFieldUpdater.newUpdater(AtomicUpdaterTestClass.class, Object.class, "o");
+ referenceUpdater.set(inst, "42");
+ System.out.println(inst.o);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/assistant/ReflectiveCallExtractorTest.java b/src/test/java/com/android/tools/r8/assistant/ReflectiveCallExtractorTest.java
index ff6ca05..374407f 100644
--- a/src/test/java/com/android/tools/r8/assistant/ReflectiveCallExtractorTest.java
+++ b/src/test/java/com/android/tools/r8/assistant/ReflectiveCallExtractorTest.java
@@ -45,7 +45,7 @@
@Test
public void testGuava() throws Exception {
- test(ToolHelper.GUAVA_JRE, 18, 20);
+ test(ToolHelper.GUAVA_JRE, 21, 17);
}
@Test
@@ -64,7 +64,7 @@
"dump_app.zip");
Path programArchive =
CompilerDump.fromArchive(zip, temp.newFolder().toPath()).getProgramArchive();
- test(programArchive, 23, 26);
+ test(programArchive, 26, 23);
}
private void test(Path jar, int success, int failure) throws Exception {