Skip to content

Commit dce9001

Browse files
committed
[GR-55085] Add support for object replacers referring to prior layer constants.
PullRequest: graal/18209
2 parents c6c88ce + f0f6984 commit dce9001

File tree

14 files changed

+489
-92
lines changed

14 files changed

+489
-92
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ protected final void scanArray(JavaConstant array, ScanReason prevReason) {
271271
scanningObserver.forNullArrayElement(array, arrayType, idx, reason);
272272
} else {
273273
try {
274-
JavaConstant element = bb.getUniverse().getHostedValuesProvider().forObject(bb.getUniverse().replaceObject(e));
274+
JavaConstant element = bb.getUniverse().replaceObjectWithConstant(e);
275275
scanArrayElement(array, arrayType, reason, idx, element);
276276
} catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) {
277277
unsupportedFeatureDuringConstantScan(bb, bb.getUniverse().getHostedValuesProvider().forObject(e), ex, reason);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ public JavaConstant replaceObject(JavaConstant value) {
7676
}
7777
if (value.getJavaKind() == JavaKind.Object) {
7878
Object oldObject = asObject(Object.class, value);
79-
Object newObject = universe.replaceObject(oldObject);
80-
if (newObject != oldObject) {
81-
return validateReplacedConstant(forObject(newObject));
79+
JavaConstant replacedConstant = universe.replaceObjectWithConstant(oldObject);
80+
if (!replacedConstant.equals(value)) {
81+
return validateReplacedConstant(replacedConstant);
8282
}
8383
}
8484
return value;

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,9 +413,9 @@ private Optional<JavaConstant> maybeReplace(JavaConstant constant, ScanReason re
413413
/* Run all registered object replacers. */
414414
if (constant.getJavaKind() == JavaKind.Object) {
415415
try {
416-
Object replaced = universe.replaceObject(unwrapped);
417-
if (replaced != unwrapped) {
418-
return Optional.of(hostedValuesProvider.validateReplacedConstant(universe.getHostedValuesProvider().forObject(replaced)));
416+
JavaConstant replaced = universe.replaceObjectWithConstant(unwrapped);
417+
if (!replaced.equals(constant)) {
418+
return Optional.of(hostedValuesProvider.validateReplacedConstant(replaced));
419419
}
420420
} catch (UnsupportedFeatureException e) {
421421
/* Enhance the unsupported feature message with the object trace and rethrow. */

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
4848
import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier;
4949
import com.oracle.graal.pointsto.heap.HostedValuesProvider;
50+
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
5051
import com.oracle.graal.pointsto.heap.ImageHeapScanner;
5152
import com.oracle.graal.pointsto.heap.ImageLayerLoader;
5253
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
@@ -103,6 +104,7 @@ public class AnalysisUniverse implements Universe {
103104
protected final SubstitutionProcessor substitutions;
104105

105106
private Function<Object, Object>[] objectReplacers;
107+
private Function<Object, ImageHeapConstant>[] objectToConstantReplacers;
106108

107109
private SubstitutionProcessor[] featureSubstitutions;
108110
private SubstitutionProcessor[] featureNativeSubstitutions;
@@ -142,6 +144,7 @@ public AnalysisUniverse(HostVM hostVM, JavaKind wordKind, AnalysisPolicy analysi
142144

143145
sealed = false;
144146
objectReplacers = (Function<Object, Object>[]) new Function<?, ?>[0];
147+
objectToConstantReplacers = (Function<Object, ImageHeapConstant>[]) new Function<?, ?>[0];
145148
featureSubstitutions = new SubstitutionProcessor[0];
146149
featureNativeSubstitutions = new SubstitutionProcessor[0];
147150
}
@@ -565,6 +568,12 @@ public void registerObjectReplacer(Function<Object, Object> replacer) {
565568
objectReplacers[objectReplacers.length - 1] = replacer;
566569
}
567570

571+
public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant> replacer) {
572+
assert replacer != null;
573+
objectToConstantReplacers = Arrays.copyOf(objectToConstantReplacers, objectToConstantReplacers.length + 1);
574+
objectToConstantReplacers[objectToConstantReplacers.length - 1] = replacer;
575+
}
576+
568577
public void registerFeatureSubstitution(SubstitutionProcessor substitution) {
569578
SubstitutionProcessor[] subs = featureSubstitutions;
570579
subs = Arrays.copyOf(subs, subs.length + 1);
@@ -587,22 +596,56 @@ public SubstitutionProcessor[] getFeatureNativeSubstitutions() {
587596
return featureNativeSubstitutions;
588597
}
589598

599+
public Object replaceObject(Object source) {
600+
return replaceObject0(source, false);
601+
}
602+
603+
public JavaConstant replaceObjectWithConstant(Object source) {
604+
assert !(source instanceof ImageHeapConstant) : source;
605+
606+
var replacedObject = replaceObject0(source, true);
607+
if (replacedObject instanceof ImageHeapConstant constant) {
608+
return constant;
609+
}
610+
611+
return getHostedValuesProvider().forObject(replacedObject);
612+
}
613+
590614
/**
591-
* Invokes all registered object replacers for an object.
615+
* Invokes all registered object replacers and "object to constant" replacers for an object.>
616+
*
617+
* <p>
618+
* The "object to constant" replacer is allowed to successfully complete only when
619+
* {@code allowObjectToConstantReplacement} is true. When
620+
* {@code allowObjectToConstantReplacement} is false, if any "object to constant" replacer is
621+
* triggered we throw an error.
592622
*
593623
* @param source The source object
624+
* @param allowObjectToConstantReplacement whether object to constant replacement is supported
594625
* @return The replaced object or the original source, if the source is not replaced by any
595626
* registered replacer.
596627
*/
597-
public Object replaceObject(Object source) {
628+
private Object replaceObject0(Object source, boolean allowObjectToConstantReplacement) {
598629
if (source == null) {
599630
return null;
600631
}
632+
601633
Object destination = source;
602634
for (Function<Object, Object> replacer : objectReplacers) {
603635
destination = replacer.apply(destination);
604636
}
605-
return destination;
637+
638+
ImageHeapConstant ihc = null;
639+
for (Function<Object, ImageHeapConstant> replacer : objectToConstantReplacers) {
640+
var result = replacer.apply(destination);
641+
if (result != null) {
642+
AnalysisError.guarantee(allowObjectToConstantReplacement, "Object to constant replacement has been triggered from an unsupported location");
643+
AnalysisError.guarantee(ihc == null, "Multiple object to constant replacers have been trigger on a single object %s %s %s", destination, ihc, result);
644+
ihc = result;
645+
}
646+
}
647+
648+
return ihc == null ? destination : ihc;
606649
}
607650

608651
public void registerOverrideReachabilityNotification(AnalysisMethod declaredMethod, MethodOverrideReachableNotification notification) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ForkJoinPoolFeature.java

Lines changed: 0 additions & 52 deletions
This file was deleted.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,22 @@
3232
import java.io.InputStream;
3333
import java.io.PrintStream;
3434
import java.io.UnsupportedEncodingException;
35+
import java.util.EnumSet;
3536
import java.util.Objects;
37+
import java.util.concurrent.atomic.AtomicBoolean;
3638

3739
import org.graalvm.nativeimage.ImageSingletons;
40+
import org.graalvm.nativeimage.Platform;
41+
import org.graalvm.nativeimage.Platforms;
3842
import org.graalvm.nativeimage.hosted.Feature;
3943

44+
import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton;
45+
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
46+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
47+
import com.oracle.svm.core.util.VMError;
48+
49+
import jdk.graal.compiler.api.replacements.Fold;
50+
4051
/**
4152
* This class provides replacement values for the {@link System#in}, {@link System#out}, and
4253
* {@link System#err} streams at run time. We want a fresh set of objects, so that any buffers
@@ -47,11 +58,14 @@
4758
* This can be customized by calling {@link #setIn}, {@link #setOut}, and {@link #setErr} before the
4859
* static analysis starts, i.e., in a {@link Feature#beforeAnalysis} method.
4960
*/
50-
public final class SystemInOutErrSupport {
61+
public final class SystemInOutErrSupport implements InitialLayerOnlyImageSingleton {
5162
private InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in));
5263
private PrintStream out = newPrintStream(new FileOutputStream(FileDescriptor.out), System.getProperty("sun.stdout.encoding"));
5364
private PrintStream err = newPrintStream(new FileOutputStream(FileDescriptor.err), System.getProperty("sun.stderr.encoding"));
5465

66+
@Platforms(Platform.HOSTED_ONLY.class) //
67+
final AtomicBoolean isSealed = new AtomicBoolean(false);
68+
5569
/* Create `PrintStream` in the same way as `System.newPrintStream`. */
5670
private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
5771
if (enc != null) {
@@ -63,32 +77,66 @@ private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
6377
return new PrintStream(new BufferedOutputStream(fos, 128), true);
6478
}
6579

80+
public void seal() {
81+
if (!isSealed.getPlain()) {
82+
isSealed.set(true);
83+
}
84+
}
85+
86+
public void checkSealed() {
87+
VMError.guarantee(!isSealed.get(), "SystemInOurErrorSupport is already sealed");
88+
}
89+
90+
private static SystemInOutErrSupport singleton() {
91+
return ImageSingletons.lookup(SystemInOutErrSupport.class);
92+
}
93+
94+
@Fold
6695
public InputStream in() {
96+
seal();
6797
return in;
6898
}
6999

100+
@Platforms(Platform.HOSTED_ONLY.class)
70101
public static void setIn(InputStream in) {
71-
ImageSingletons.lookup(SystemInOutErrSupport.class).in = Objects.requireNonNull(in);
102+
var support = singleton();
103+
support.checkSealed();
104+
support.in = Objects.requireNonNull(in);
72105
}
73106

107+
@Fold
74108
public PrintStream out() {
109+
seal();
75110
return out;
76111
}
77112

113+
@Platforms(Platform.HOSTED_ONLY.class)
78114
public static void setOut(PrintStream out) {
79-
ImageSingletons.lookup(SystemInOutErrSupport.class).out = Objects.requireNonNull(out);
115+
var support = singleton();
116+
support.checkSealed();
117+
support.out = Objects.requireNonNull(out);
80118
}
81119

120+
@Fold
82121
public PrintStream err() {
122+
seal();
83123
return err;
84124
}
85125

126+
@Platforms(Platform.HOSTED_ONLY.class)
86127
public static void setErr(PrintStream err) {
87-
ImageSingletons.lookup(SystemInOutErrSupport.class).err = Objects.requireNonNull(err);
128+
var support = singleton();
129+
support.checkSealed();
130+
support.err = Objects.requireNonNull(err);
131+
}
132+
133+
@Override
134+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
135+
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
88136
}
89137
}
90138

91139
@SuppressWarnings("unused")
92-
class SystemInOutErrFeature implements Feature {
140+
class SystemInOutErrFeature implements Feature, FeatureSingleton {
93141
/* Dummy for backward compatibility. */
94142
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
import com.oracle.graal.pointsto.BigBang;
5656
import com.oracle.graal.pointsto.ObjectScanner;
57+
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
5758
import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
5859
import com.oracle.graal.pointsto.meta.AnalysisField;
5960
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
@@ -293,6 +294,15 @@ public void registerObjectReplacer(Function<Object, Object> replacer) {
293294
getUniverse().registerObjectReplacer(replacer);
294295
}
295296

297+
/**
298+
* Register an object replacer which may return an ImageHeapConstant. Note only one replacer
299+
* can be triggered for a given object; otherwise an error will be thrown. Too, if the
300+
* object should not be replaced then {@code null} should be returned.
301+
*/
302+
public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant> replacer) {
303+
getUniverse().registerObjectToConstantReplacer(replacer);
304+
}
305+
296306
/**
297307
* Register a callback that is executed when an object of the specified type or any of its
298308
* subtypes is marked as reachable.

0 commit comments

Comments
 (0)