Skip to content

Commit 3ed03f3

Browse files
committed
[GR-68082] Refactor class inclusion policy. Reduce core reflection usage.
PullRequest: graal/21640
2 parents 35b4518 + 604b1a3 commit 3ed03f3

File tree

24 files changed

+588
-368
lines changed

24 files changed

+588
-368
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
417417
// Primitive Class case returns null
418418
PiNode klassNonNull = helper.emitNullReturnGuard(klass, nullValue, GraalDirectives.UNLIKELY_PROBABILITY);
419419

420-
// if ((Klass::_access_flags & Modifer.INTERCAE) != 0) return null
420+
// if ((Klass::_access_flags & Modifer.INTERFACE) != 0) return null
421421
ValueNode accessFlags = helper.readKlassAccessFlags(klassNonNull);
422422
LogicNode test = IntegerTestNode.create(accessFlags, ConstantNode.forInt(Modifier.INTERFACE), NodeView.DEFAULT);
423423
helper.emitReturnIfNot(test, nullValue, GraalDirectives.UNLIKELY_PROBABILITY);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ public Field originalField(ResolvedJavaField field) {
143143
Objects.requireNonNull(field);
144144
GraalError.guarantee(field instanceof HotSpotResolvedJavaField, "Unexpected implementation class: %s", field.getClass());
145145

146+
if (field.isInternal()) {
147+
/* internal fields never have a corresponding java.lang.reflect.Field. */
148+
return null;
149+
}
146150
return runtime().getMirror(field);
147151
}
148152
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,13 @@
2525
package com.oracle.graal.pointsto;
2626

2727
import java.io.PrintWriter;
28-
import java.lang.reflect.Constructor;
29-
import java.lang.reflect.Field;
30-
import java.lang.reflect.Method;
31-
import java.util.Arrays;
3228
import java.util.Collections;
3329
import java.util.List;
3430
import java.util.function.Function;
35-
import java.util.stream.Stream;
3631

3732
import org.graalvm.nativeimage.hosted.Feature;
3833

39-
import com.oracle.graal.pointsto.ClassInclusionPolicy.LayeredBaseImageInclusionPolicy;
34+
import com.oracle.graal.pointsto.ClassInclusionPolicy.SharedLayerImageInclusionPolicy;
4035
import com.oracle.graal.pointsto.api.HostVM;
4136
import com.oracle.graal.pointsto.api.PointstoOptions;
4237
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
@@ -68,7 +63,9 @@
6863
import jdk.vm.ci.code.BytecodeFrame;
6964
import jdk.vm.ci.code.BytecodePosition;
7065
import jdk.vm.ci.meta.ConstantReflectionProvider;
66+
import jdk.vm.ci.meta.ResolvedJavaField;
7167
import jdk.vm.ci.meta.ResolvedJavaMethod;
68+
import jdk.vm.ci.meta.ResolvedJavaType;
7269

7370
/**
7471
* This abstract class is shared between Reachability and Points-to. It contains generic methods
@@ -103,6 +100,8 @@ public abstract class AbstractAnalysisEngine implements BigBang {
103100
protected final Timer analysisTimer;
104101
protected final Timer verifyHeapTimer;
105102
protected final ClassInclusionPolicy classInclusionPolicy;
103+
private static final ResolvedJavaMethod[] NO_METHODS = new ResolvedJavaMethod[]{};
104+
private static final ResolvedJavaField[] NO_FIELDS = new ResolvedJavaField[]{};
106105

107106
@SuppressWarnings("this-escape")
108107
public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider,
@@ -208,7 +207,7 @@ private boolean analysisModified() {
208207
* After the analysis reaches a stable state check if the shadow heap contains all
209208
* objects reachable from roots. If this leads to analysis state changes, an additional
210209
* analysis iteration will be run.
211-
*
210+
*
212211
* We reuse the analysis executor, which at this point should be in before-start state:
213212
* the analysis finished and it re-initialized the executor for the next iteration. The
214213
* verifier controls the life cycle of the executor: it starts it and then waits until
@@ -259,7 +258,7 @@ public void profileConstantObject(AnalysisType type) {
259258
}
260259

261260
public boolean isBaseLayerAnalysisEnabled() {
262-
return classInclusionPolicy instanceof LayeredBaseImageInclusionPolicy;
261+
return classInclusionPolicy instanceof SharedLayerImageInclusionPolicy;
263262
}
264263

265264
@Override
@@ -352,30 +351,58 @@ public final boolean executorIsStarted() {
352351
}
353352

354353
@Override
355-
public void registerTypeForBaseImage(Class<?> cls) {
356-
if (getOrDefault(cls, classInclusionPolicy::isClassIncluded, false)) {
357-
classInclusionPolicy.includeClass(cls);
358-
Stream.concat(Arrays.stream(getOrDefault(cls, Class::getDeclaredConstructors, new Constructor<?>[0])), Arrays.stream(getOrDefault(cls, Class::getDeclaredMethods, new Method[0])))
359-
.filter(classInclusionPolicy::isMethodIncluded)
360-
.forEach(classInclusionPolicy::includeMethod);
361-
Arrays.stream(getOrDefault(cls, Class::getDeclaredFields, new Field[0]))
362-
.filter(classInclusionPolicy::isFieldIncluded)
363-
.forEach(classInclusionPolicy::includeField);
354+
public void tryRegisterTypeForBaseImage(ResolvedJavaType type) {
355+
if (tryApply(type, classInclusionPolicy::isOriginalTypeIncluded, false)) {
356+
classInclusionPolicy.includeType(type);
357+
ResolvedJavaMethod[] constructors = tryApply(type, t -> t.getDeclaredConstructors(false), NO_METHODS);
358+
ResolvedJavaMethod[] methods = tryApply(type, t -> t.getDeclaredMethods(false), NO_METHODS);
359+
for (ResolvedJavaMethod[] executables : List.of(constructors, methods)) {
360+
for (ResolvedJavaMethod executable : executables) {
361+
if (classInclusionPolicy.isOriginalMethodIncluded(executable)) {
362+
classInclusionPolicy.includeMethod(executable);
363+
}
364+
}
365+
}
366+
ResolvedJavaField[] instanceFields = tryApply(type, t -> t.getInstanceFields(false), NO_FIELDS);
367+
ResolvedJavaField[] staticFields = tryApply(type, ResolvedJavaType::getStaticFields, NO_FIELDS);
368+
for (ResolvedJavaField[] fields : List.of(instanceFields, staticFields)) {
369+
for (ResolvedJavaField field : fields) {
370+
if (classInclusionPolicy.isOriginalFieldIncluded(field)) {
371+
classInclusionPolicy.includeField(field);
372+
}
373+
}
374+
}
364375
}
365376
}
366377

367378
@Override
368-
public void registerMethodForBaseImage(AnalysisMethod method) {
369-
if (classInclusionPolicy.isMethodIncluded(method)) {
379+
public void tryRegisterMethodForBaseImage(AnalysisMethod method) {
380+
if (classInclusionPolicy.isAnalysisMethodIncluded(method)) {
370381
classInclusionPolicy.includeMethod(method);
371382
}
372383
}
373384

374-
public static <T, U> U getOrDefault(T cls, Function<T, U> getMembers, U backup) {
385+
@Override
386+
public void tryRegisterFieldForBaseImage(AnalysisField field) {
387+
if (classInclusionPolicy.isAnalysisFieldIncluded(field)) {
388+
classInclusionPolicy.includeField(field);
389+
}
390+
}
391+
392+
/**
393+
* Applies {@code function} to {@code type} and returns the result or, if
394+
* {@link NoClassDefFoundError} or {@link IncompatibleClassChangeError} thrown when applying the
395+
* function, returns {@code fallback}.
396+
* <p>
397+
* The error handling allows for querying members (fields, methods or constructors) of a class
398+
* where a member signature refers to a type that is unresolvable due to an incomplete class
399+
* path. Such resolution errors need to be ignored when building a shared layer.
400+
*/
401+
private static <U> U tryApply(ResolvedJavaType type, Function<ResolvedJavaType, U> function, U fallback) {
375402
try {
376-
return getMembers.apply(cls);
403+
return function.apply(type);
377404
} catch (NoClassDefFoundError | IncompatibleClassChangeError e) {
378-
return backup;
405+
return fallback;
379406
}
380407
}
381408

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import jdk.graal.compiler.word.WordTypes;
4646
import jdk.vm.ci.code.BytecodePosition;
4747
import jdk.vm.ci.meta.ConstantReflectionProvider;
48+
import jdk.vm.ci.meta.ResolvedJavaType;
4849

4950
/**
5051
* Central static analysis interface that groups together the functionality of reachability analysis
@@ -139,12 +140,17 @@ default AnalysisMethod fallbackResolveConcreteMethod(AnalysisType resolvingType,
139140
}
140141

141142
@SuppressWarnings("unused")
142-
default void registerTypeForBaseImage(Class<?> cls) {
143+
default void tryRegisterTypeForBaseImage(ResolvedJavaType type) {
143144

144145
}
145146

146147
@SuppressWarnings("unused")
147-
default void registerMethodForBaseImage(AnalysisMethod method) {
148+
default void tryRegisterMethodForBaseImage(AnalysisMethod method) {
149+
150+
}
151+
152+
@SuppressWarnings("unused")
153+
default void tryRegisterFieldForBaseImage(AnalysisField field) {
148154

149155
}
150156
}

0 commit comments

Comments
 (0)