Skip to content

Commit 4271c56

Browse files
committed
svm: migrate DebuggerFeature from core reflection to JVMCI based API
1 parent dd7d545 commit 4271c56

File tree

1 file changed

+53
-60
lines changed

1 file changed

+53
-60
lines changed

substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/DebuggerFeature.java

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@
3636
import static com.oracle.svm.interpreter.metadata.InterpreterUniverseImpl.toHexString;
3737

3838
import java.io.IOException;
39-
import java.lang.reflect.Constructor;
40-
import java.lang.reflect.Field;
41-
import java.lang.reflect.Method;
4239
import java.lang.reflect.Modifier;
4340
import java.nio.charset.StandardCharsets;
4441
import java.nio.file.FileSystems;
@@ -67,8 +64,8 @@
6764
import com.oracle.graal.pointsto.ObjectScanner.ScanReason;
6865
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
6966
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
70-
import com.oracle.svm.util.OriginalClassProvider;
7167
import com.oracle.graal.pointsto.meta.AnalysisField;
68+
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
7269
import com.oracle.graal.pointsto.meta.AnalysisMethod;
7370
import com.oracle.graal.pointsto.meta.AnalysisType;
7471
import com.oracle.svm.core.BuildArtifacts;
@@ -111,7 +108,7 @@
111108
import com.oracle.svm.interpreter.metadata.ReferenceConstant;
112109
import com.oracle.svm.interpreter.metadata.serialization.SerializationContext;
113110
import com.oracle.svm.interpreter.metadata.serialization.Serializers;
114-
import com.oracle.svm.util.ReflectionUtil;
111+
import com.oracle.svm.util.JVMCIReflectionUtil;
115112

116113
import jdk.graal.compiler.api.replacements.SnippetReflectionProvider;
117114
import jdk.graal.compiler.core.common.SuppressFBWarnings;
@@ -130,6 +127,7 @@
130127
import jdk.vm.ci.meta.PrimitiveConstant;
131128
import jdk.vm.ci.meta.ResolvedJavaField;
132129
import jdk.vm.ci.meta.ResolvedJavaMethod;
130+
import jdk.vm.ci.meta.ResolvedJavaType;
133131
import jdk.vm.ci.meta.UnresolvedJavaMethod;
134132

135133
/**
@@ -144,9 +142,9 @@
144142
@Platforms(Platform.HOSTED_ONLY.class)
145143
@AutomaticallyRegisteredFeature
146144
public class DebuggerFeature implements InternalFeature {
147-
private Method enterInterpreterMethod;
145+
private AnalysisMethod enterInterpreterMethod;
148146
private InterpreterStubTable enterStubTable = null;
149-
private final List<Class<?>> classesUsedByInterpreter = new ArrayList<>();
147+
private final List<ResolvedJavaType> classesUsedByInterpreter = new ArrayList<>();
150148
private Set<AnalysisMethod> methodsProcessedDuringAnalysis;
151149
private InvocationPlugins invocationPlugins;
152150
private static final String SYNTHETIC_ASSERTIONS_DISABLED_FIELD_NAME = "$assertionsDisabled";
@@ -165,9 +163,9 @@ public List<Class<? extends Feature>> getRequiredFeatures() {
165163
SymbolsFeature.class);
166164
}
167165

168-
private static Class<?> getArgumentClass(GraphBuilderContext b, ResolvedJavaMethod targetMethod, int parameterIndex, ValueNode arg) {
166+
private static ResolvedJavaType getArgumentType(GraphBuilderContext b, ResolvedJavaMethod targetMethod, int parameterIndex, ValueNode arg) {
169167
SubstrateGraphBuilderPlugins.checkParameterUsage(arg.isConstant(), b, targetMethod, parameterIndex, "parameter is not a compile time constant");
170-
return OriginalClassProvider.getJavaClass(b.getConstantReflection().asJavaType(arg.asJavaConstant()));
168+
return b.getConstantReflection().asJavaType(arg.asJavaConstant());
171169
}
172170

173171
@Override
@@ -178,9 +176,9 @@ public void registerInvocationPlugins(Providers providers, GraphBuilderConfigura
178176
r.register(new InvocationPlugin.RequiredInvocationPlugin("markKlass", Class.class) {
179177
@Override
180178
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1) {
181-
Class<?> targetKlass = getArgumentClass(b, targetMethod, 1, arg1);
182-
InterpreterUtil.log("[invocation plugin] Adding %s", targetKlass);
183-
classesUsedByInterpreter.add(targetKlass);
179+
ResolvedJavaType targetType = getArgumentType(b, targetMethod, 1, arg1);
180+
InterpreterUtil.log("[invocation plugin] Adding %s", targetType.getUnqualifiedName());
181+
classesUsedByInterpreter.add(targetType);
184182

185183
/* no-op in compiled code */
186184
return true;
@@ -198,33 +196,32 @@ public void afterRegistration(AfterRegistrationAccess access) {
198196
@Override
199197
public void beforeAnalysis(BeforeAnalysisAccess access) {
200198
FeatureImpl.BeforeAnalysisAccessImpl accessImpl = (FeatureImpl.BeforeAnalysisAccessImpl) access;
199+
AnalysisMetaAccess metaAccess = accessImpl.getMetaAccess();
201200

202-
try {
203-
enterInterpreterMethod = InterpreterStubSection.class.getMethod("enterMethodInterpreterStub", int.class, Pointer.class);
204-
accessImpl.registerAsRoot(enterInterpreterMethod, true, "stub for interpreter");
201+
AnalysisType aInterpreterStubSection = metaAccess.lookupJavaType(InterpreterStubSection.class);
202+
enterInterpreterMethod = (AnalysisMethod) JVMCIReflectionUtil.getDeclaredMethod(metaAccess, aInterpreterStubSection, "enterMethodInterpreterStub", int.class, Pointer.class);
203+
accessImpl.registerAsRoot(enterInterpreterMethod, true, "stub for interpreter");
205204

206-
// Holds references that must be kept alive in the image heap.
207-
access.registerAsAccessed(DebuggerSupport.class.getDeclaredField("referencesInImage"));
208-
access.registerAsAccessed(DebuggerSupport.class.getDeclaredField("methodPointersInImage"));
205+
// Holds references that must be kept alive in the image heap.
206+
AnalysisType aDebuggerSupport = metaAccess.lookupJavaType(DebuggerSupport.class);
207+
accessImpl.registerAsAccessed((AnalysisField) JVMCIReflectionUtil.getDeclaredField(aDebuggerSupport, "referencesInImage"),
208+
"Holds references that must be kept alive in the image heap.");
209+
accessImpl.registerAsAccessed((AnalysisField) JVMCIReflectionUtil.getDeclaredField(aDebuggerSupport, "methodPointersInImage"),
210+
"Holds references that must be kept alive in the image heap.");
209211

210-
accessImpl.registerAsRoot(System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class), true,
211-
"Allow interpreting methods that call System.arraycopy");
212-
} catch (NoSuchMethodException | NoSuchFieldException e) {
213-
throw VMError.shouldNotReachHere(e);
214-
}
212+
AnalysisType aSystem = metaAccess.lookupJavaType(System.class);
213+
accessImpl.registerAsRoot((AnalysisMethod) JVMCIReflectionUtil.getDeclaredMethod(metaAccess, aSystem, "arraycopy", Object.class, int.class, Object.class, int.class, int.class),
214+
true, "Allow interpreting methods that call System.arraycopy");
215215

216216
registerStringConcatenation(accessImpl);
217217

218218
// GR-53734: Known issues around reachability
219-
try {
220-
// JDK code introduced a new optional intrinsic:
221-
// https://github.com/openjdk/jdk22u/commit/a4e9168bab1c2872ce2dbc7971a45c259270271f
222-
// consider DualPivotQuicksort.java:268, int.class is not needed if the sort helper
223-
// is inlined, therefore it's not needed. Still needed for interpreter execution.
224-
access.registerAsAccessed(Integer.class.getField("TYPE"));
225-
} catch (NoSuchFieldException e) {
226-
throw VMError.shouldNotReachHere(e);
227-
}
219+
// JDK code introduced a new optional intrinsic:
220+
// https://github.com/openjdk/jdk22u/commit/a4e9168bab1c2872ce2dbc7971a45c259270271f
221+
// consider DualPivotQuicksort.java:268, int.class is not needed if the sort helper
222+
// is inlined, therefore it's not needed. Still needed for interpreter execution.
223+
AnalysisType aInteger = metaAccess.lookupJavaType(Integer.class);
224+
accessImpl.registerAsAccessed((AnalysisField) JVMCIReflectionUtil.getDeclaredField(aInteger, "TYPE"), "Read by the interpreter");
228225

229226
methodsProcessedDuringAnalysis = new HashSet<>();
230227

@@ -247,20 +244,18 @@ private static void registerStringConcatenation(FeatureImpl.BeforeAnalysisAccess
247244
* These registrations enable the interpreter to "interpret" StringBuilder-based String
248245
* concatenation optimized away by the compiler.
249246
*/
250-
try {
251-
List<Method> appendMethods = Arrays.stream(StringBuilder.class.getDeclaredMethods())
252-
.filter(m -> "append".equals(m.getName()))
253-
.collect(Collectors.toList());
254-
for (Method m : appendMethods) {
255-
accessImpl.registerAsRoot(m, false, "string concat in interpreter");
256-
}
257-
for (Constructor<?> c : StringBuilder.class.getDeclaredConstructors()) {
258-
accessImpl.registerAsRoot(c, true, "string concat in interpreter");
259-
}
260-
accessImpl.registerAsRoot(StringBuilder.class.getConstructor(), true, "string concat in interpreter");
261-
} catch (NoSuchMethodException e) {
262-
throw new RuntimeException(e);
247+
AnalysisMetaAccess metaAccess = accessImpl.getMetaAccess();
248+
AnalysisType aStringBuilder = metaAccess.lookupJavaType(StringBuilder.class);
249+
List<AnalysisMethod> appendMethods = Arrays.stream(aStringBuilder.getDeclaredMethods(false))
250+
.filter(m -> "append".equals(m.getName())).toList();
251+
for (AnalysisMethod m : appendMethods) {
252+
accessImpl.registerAsRoot(m, false, "string concat in interpreter");
253+
}
254+
for (AnalysisMethod c : aStringBuilder.getDeclaredConstructors(false)) {
255+
accessImpl.registerAsRoot(c, true, "string concat in interpreter");
263256
}
257+
AnalysisMethod aMethod = (AnalysisMethod) JVMCIReflectionUtil.getDeclaredConstructor(metaAccess, aStringBuilder);
258+
accessImpl.registerAsRoot(aMethod, true, "string concat in interpreter");
264259
}
265260

266261
static boolean isReachable(AnalysisMethod m) {
@@ -299,13 +294,13 @@ public void duringAnalysis(DuringAnalysisAccess access) {
299294

300295
if (!classesUsedByInterpreter.isEmpty()) {
301296
access.requireAnalysisIteration();
302-
for (Class<?> k : classesUsedByInterpreter) {
303-
accessImpl.registerAsUsed(k);
304-
Arrays.stream(k.getDeclaredMethods()).filter(m -> m.getName().startsWith("test")).forEach(m -> {
305-
AnalysisMethod aMethod = accessImpl.getMetaAccess().lookupJavaMethod(m);
297+
for (ResolvedJavaType k : classesUsedByInterpreter) {
298+
AnalysisType aType = k instanceof AnalysisType analysisType ? analysisType : accessImpl.getUniverse().lookup(k);
299+
accessImpl.registerAsUsed(aType, "used by interpreter");
300+
Arrays.stream(aType.getDeclaredMethods(false)).filter(m -> m.getName().startsWith("test")).forEach(aMethod -> {
306301
VMError.guarantee(!aMethod.isConstructor());
307302
accessImpl.registerAsRoot(aMethod, aMethod.isConstructor(), "reached due to interpreter directive");
308-
InterpreterUtil.log("[during analysis] Adding method %s", m);
303+
InterpreterUtil.log("[during analysis] Adding method %s", aMethod);
309304
});
310305
}
311306
classesUsedByInterpreter.clear();
@@ -440,7 +435,7 @@ public void beforeCompilation(BeforeCompilationAccess access) {
440435
FeatureImpl.BeforeCompilationAccessImpl accessImpl = (FeatureImpl.BeforeCompilationAccessImpl) access;
441436
HostedUniverse hUniverse = accessImpl.getUniverse();
442437
HostedMetaAccess hMetaAccess = accessImpl.getMetaAccess();
443-
MetaAccessProvider aMetaAccess = hMetaAccess.getWrapped();
438+
AnalysisMetaAccess aMetaAccess = (AnalysisMetaAccess) hMetaAccess.getWrapped();
444439
BuildTimeInterpreterUniverse iUniverse = BuildTimeInterpreterUniverse.singleton();
445440

446441
for (HostedType hType : hUniverse.getTypes()) {
@@ -501,20 +496,18 @@ public void beforeCompilation(BeforeCompilationAccess access) {
501496

502497
iUniverse.purgeUnreachable(hMetaAccess);
503498

504-
Field vtableHolderField = ReflectionUtil.lookupField(InterpreterResolvedObjectType.class, "vtableHolder");
499+
AnalysisField vtableHolderField = (AnalysisField) JVMCIReflectionUtil.getDeclaredField(aMetaAccess.lookupJavaType(InterpreterResolvedObjectType.class), "vtableHolder");
505500
ScanReason reason = new OtherReason("Manual rescan triggered before compilation from " + DebuggerFeature.class);
506501
for (HostedType hostedType : hUniverse.getTypes()) {
507502
iUniverse.mirrorSVMVTable(hostedType, objectType -> accessImpl.getHeapScanner().rescanField(objectType, vtableHolderField, reason));
508503
}
509504

510505
// Allow methods that call System.arraycopy to be interpreted.
511-
try {
512-
HostedMethod arraycopy = hMetaAccess.lookupJavaMethod(
513-
System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class));
514-
SubstrateCompilationDirectives.singleton().registerForcedCompilation(arraycopy);
515-
} catch (NoSuchMethodException e) {
516-
throw new RuntimeException(e);
517-
}
506+
507+
HostedType systemClass = hMetaAccess.lookupJavaType(System.class);
508+
AnalysisMethod arraycopy = (AnalysisMethod) JVMCIReflectionUtil.getDeclaredMethod(aMetaAccess,
509+
systemClass.getWrapped(), "arraycopy", Object.class, int.class, Object.class, int.class, int.class);
510+
SubstrateCompilationDirectives.singleton().registerForcedCompilation(arraycopy);
518511
}
519512

520513
@Override
@@ -768,7 +761,7 @@ public void beforeImageWrite(BeforeImageWriteAccess access) {
768761

769762
InterpreterStubSection stubSection = ImageSingletons.lookup(InterpreterStubSection.class);
770763

771-
stubSection.markEnterStubPatch(accessImpl.getHostedMetaAccess().lookupJavaMethod(enterInterpreterMethod));
764+
stubSection.markEnterStubPatch(enterInterpreterMethod);
772765
enterStubTable.writeMetadataHashString(hashString.getBytes(StandardCharsets.UTF_8));
773766
}
774767

0 commit comments

Comments
 (0)