Model ClassNewInstance in R8 Assistant
Bug: b/428836085
Change-Id: Ib7822f855d1d607d508c6637b56af316fc123e83
diff --git a/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ClassNewInstance.java b/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ClassNewInstance.java
new file mode 100644
index 0000000..dfdab8d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ClassNewInstance.java
@@ -0,0 +1,47 @@
+// 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.postprocessing.model;
+
+import com.android.tools.r8.assistant.runtime.ReflectiveEventType;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.shaking.KeepInfoCollectionExported;
+
+public class ClassNewInstance extends ReflectiveEvent {
+
+ private final DexType type;
+
+ protected ClassNewInstance(
+ ReflectiveEventType eventType, String[] stack, String[] args, DexItemFactory factory) {
+ super(eventType, stack);
+ type = toType(args[0], factory);
+ }
+
+ public DexType getType() {
+ return type;
+ }
+
+ @Override
+ public boolean isClassNewInstance() {
+ return true;
+ }
+
+ @Override
+ public ClassNewInstance asClassNewInstance() {
+ return this;
+ }
+
+ @Override
+ public String getContentsString() {
+ return type.toSourceString();
+ }
+
+ @Override
+ public boolean isKeptBy(KeepInfoCollectionExported keepInfoCollectionExported) {
+ // TODO(b/428836085): Check inner properties of the keep rules, holder, type and name may have
+ // to be preserved.
+ return keepInfoCollectionExported.getKeepClassInfo(type.asTypeReference()) != null;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ReflectiveEvent.java b/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ReflectiveEvent.java
index 26090d0..d217231 100644
--- a/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ReflectiveEvent.java
+++ b/src/main/java/com/android/tools/r8/assistant/postprocessing/model/ReflectiveEvent.java
@@ -68,6 +68,14 @@
return null;
}
+ public boolean isClassNewInstance() {
+ return false;
+ }
+
+ public ClassNewInstance asClassNewInstance() {
+ return null;
+ }
+
public boolean isClassGetMembers() {
return false;
}
@@ -89,7 +97,7 @@
ReflectiveEventType eventType, String[] stack, String[] args, DexItemFactory factory) {
switch (eventType) {
case CLASS_NEW_INSTANCE:
- break;
+ return new ClassNewInstance(eventType, stack, args, factory);
case CLASS_GET_DECLARED_METHOD:
case CLASS_GET_DECLARED_FIELD:
case CLASS_GET_DECLARED_CONSTRUCTOR:
diff --git a/src/test/java/com/android/tools/r8/assistant/JavaLangClassJsonTest.java b/src/test/java/com/android/tools/r8/assistant/JavaLangClassJsonTest.java
index 5e1fbf8..ff05d32 100644
--- a/src/test/java/com/android/tools/r8/assistant/JavaLangClassJsonTest.java
+++ b/src/test/java/com/android/tools/r8/assistant/JavaLangClassJsonTest.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.assistant.postprocessing.model.ClassGetMember;
import com.android.tools.r8.assistant.postprocessing.model.ClassGetMembers;
import com.android.tools.r8.assistant.postprocessing.model.ClassGetName;
+import com.android.tools.r8.assistant.postprocessing.model.ClassNewInstance;
import com.android.tools.r8.assistant.postprocessing.model.ReflectiveEvent;
import com.android.tools.r8.assistant.runtime.ReflectiveEventType;
import com.android.tools.r8.assistant.runtime.ReflectiveOperationJsonLogger;
@@ -69,7 +70,7 @@
.assertSuccess();
List<ReflectiveEvent> reflectiveEvents =
new ReflectiveOperationJsonParser(factoryBox.get()).parse(path);
- Assert.assertEquals(29, reflectiveEvents.size());
+ Assert.assertEquals(30, reflectiveEvents.size());
assertTrue(reflectiveEvents.get(4).isClassGetMember());
ClassGetMember updater00 = reflectiveEvents.get(4).asClassGetMember();
@@ -163,6 +164,11 @@
Reference.methodFromMethod(Bar.class.getConstructor()),
updater24.getMember().asDexMethod().asMethodReference());
+ assertTrue(reflectiveEvents.get(29).isClassNewInstance());
+ ClassNewInstance updater29 = reflectiveEvents.get(29).asClassNewInstance();
+ assertEquals(ReflectiveEventType.CLASS_NEW_INSTANCE, updater29.getEventType());
+ assertEquals(Bar.class.getName(), updater29.getType().toSourceString());
+
Box<KeepInfoCollectionExported> keepInfoBox = new Box<>();
testForR8(parameters)
.addProgramClasses(JavaLangClassTestClass.class, Foo.class, Bar.class)
@@ -188,6 +194,7 @@
"public com.android.tools.r8.assistant.JavaLangClassTestClass$Bar()",
"true",
"class com.android.tools.r8.assistant.JavaLangClassTestClass$Bar",
+ "11",
"END");
KeepInfoCollectionExported keepInfoCollectionExported = keepInfoBox.get();
diff --git a/src/test/java/com/android/tools/r8/assistant/JavaLangClassTest.java b/src/test/java/com/android/tools/r8/assistant/JavaLangClassTest.java
index 374014b..ce78e14 100644
--- a/src/test/java/com/android/tools/r8/assistant/JavaLangClassTest.java
+++ b/src/test/java/com/android/tools/r8/assistant/JavaLangClassTest.java
@@ -85,6 +85,8 @@
"true",
"40",
"class com.android.tools.r8.assistant.JavaLangClassTestClass$Bar",
+ "50",
+ "11",
"END");
}
@@ -201,7 +203,7 @@
@Override
public void onClassNewInstance(Stack stack, Class<?> clazz) {
- super.onClassNewInstance(stack, clazz);
+ printNumIfTrue(clazz.getName().endsWith("Bar"), 50);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/assistant/JavaLangClassTestClass.java b/src/test/java/com/android/tools/r8/assistant/JavaLangClassTestClass.java
index a0308d6..feb74d1 100644
--- a/src/test/java/com/android/tools/r8/assistant/JavaLangClassTestClass.java
+++ b/src/test/java/com/android/tools/r8/assistant/JavaLangClassTestClass.java
@@ -52,6 +52,13 @@
Bar cast = Bar.class.cast(o);
System.out.println(Bar.class.isInstance(o));
System.out.println(Bar.class.asSubclass(Foo.class));
+ Bar newBar = null;
+ try {
+ newBar = Bar.class.newInstance();
+ System.out.println(newBar.bar());
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
System.out.println("END");
} catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) {
System.out.println("EXCEPTION " + e.getMessage());