Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ protected final void scanArray(JavaConstant array, ScanReason prevReason) {
scanningObserver.forNullArrayElement(array, arrayType, idx, reason);
} else {
try {
JavaConstant element = bb.getUniverse().getHostedValuesProvider().forObject(bb.getUniverse().replaceObject(e));
JavaConstant element = bb.getUniverse().replaceObjectWithConstant(e);
scanArrayElement(array, arrayType, reason, idx, element);
} catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) {
unsupportedFeatureDuringConstantScan(bb, bb.getUniverse().getHostedValuesProvider().forObject(e), ex, reason);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ public JavaConstant replaceObject(JavaConstant value) {
}
if (value.getJavaKind() == JavaKind.Object) {
Object oldObject = asObject(Object.class, value);
Object newObject = universe.replaceObject(oldObject);
if (newObject != oldObject) {
return validateReplacedConstant(forObject(newObject));
JavaConstant replacedConstant = universe.replaceObjectWithConstant(oldObject);
if (!replacedConstant.equals(value)) {
return validateReplacedConstant(replacedConstant);
}
}
return value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,9 @@ private Optional<JavaConstant> maybeReplace(JavaConstant constant, ScanReason re
/* Run all registered object replacers. */
if (constant.getJavaKind() == JavaKind.Object) {
try {
Object replaced = universe.replaceObject(unwrapped);
if (replaced != unwrapped) {
return Optional.of(hostedValuesProvider.validateReplacedConstant(universe.getHostedValuesProvider().forObject(replaced)));
JavaConstant replaced = universe.replaceObjectWithConstant(unwrapped);
if (!replaced.equals(constant)) {
return Optional.of(hostedValuesProvider.validateReplacedConstant(replaced));
}
} catch (UnsupportedFeatureException e) {
/* Enhance the unsupported feature message with the object trace and rethrow. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier;
import com.oracle.graal.pointsto.heap.HostedValuesProvider;
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
import com.oracle.graal.pointsto.heap.ImageHeapScanner;
import com.oracle.graal.pointsto.heap.ImageLayerLoader;
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
Expand Down Expand Up @@ -103,6 +104,7 @@ public class AnalysisUniverse implements Universe {
protected final SubstitutionProcessor substitutions;

private Function<Object, Object>[] objectReplacers;
private Function<Object, ImageHeapConstant>[] objectToConstantReplacers;

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

sealed = false;
objectReplacers = (Function<Object, Object>[]) new Function<?, ?>[0];
objectToConstantReplacers = (Function<Object, ImageHeapConstant>[]) new Function<?, ?>[0];
featureSubstitutions = new SubstitutionProcessor[0];
featureNativeSubstitutions = new SubstitutionProcessor[0];
}
Expand Down Expand Up @@ -565,6 +568,12 @@ public void registerObjectReplacer(Function<Object, Object> replacer) {
objectReplacers[objectReplacers.length - 1] = replacer;
}

public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant> replacer) {
assert replacer != null;
objectToConstantReplacers = Arrays.copyOf(objectToConstantReplacers, objectToConstantReplacers.length + 1);
objectToConstantReplacers[objectToConstantReplacers.length - 1] = replacer;
}

public void registerFeatureSubstitution(SubstitutionProcessor substitution) {
SubstitutionProcessor[] subs = featureSubstitutions;
subs = Arrays.copyOf(subs, subs.length + 1);
Expand All @@ -587,22 +596,56 @@ public SubstitutionProcessor[] getFeatureNativeSubstitutions() {
return featureNativeSubstitutions;
}

public Object replaceObject(Object source) {
return replaceObject0(source, false);
}

public JavaConstant replaceObjectWithConstant(Object source) {
assert !(source instanceof ImageHeapConstant) : source;

var replacedObject = replaceObject0(source, true);
if (replacedObject instanceof ImageHeapConstant constant) {
return constant;
}

return getHostedValuesProvider().forObject(replacedObject);
}

/**
* Invokes all registered object replacers for an object.
* Invokes all registered object replacers and "object to constant" replacers for an object.>
*
* <p>
* The "object to constant" replacer is allowed to successfully complete only when
* {@code allowObjectToConstantReplacement} is true. When
* {@code allowObjectToConstantReplacement} is false, if any "object to constant" replacer is
* triggered we throw an error.
*
* @param source The source object
* @param allowObjectToConstantReplacement whether object to constant replacement is supported
* @return The replaced object or the original source, if the source is not replaced by any
* registered replacer.
*/
public Object replaceObject(Object source) {
private Object replaceObject0(Object source, boolean allowObjectToConstantReplacement) {
if (source == null) {
return null;
}

Object destination = source;
for (Function<Object, Object> replacer : objectReplacers) {
destination = replacer.apply(destination);
}
return destination;

ImageHeapConstant ihc = null;
for (Function<Object, ImageHeapConstant> replacer : objectToConstantReplacers) {
var result = replacer.apply(destination);
if (result != null) {
AnalysisError.guarantee(allowObjectToConstantReplacement, "Object to constant replacement has been triggered from an unsupported location");
AnalysisError.guarantee(ihc == null, "Multiple object to constant replacers have been trigger on a single object %s %s %s", destination, ihc, result);
ihc = result;
}
}

return ihc == null ? destination : ihc;
}

public void registerOverrideReachabilityNotification(AnalysisMethod declaredMethod, MethodOverrideReachableNotification notification) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,22 @@
import java.io.InputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.EnumSet;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.hosted.Feature;

import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton;
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.util.VMError;

import jdk.graal.compiler.api.replacements.Fold;

/**
* This class provides replacement values for the {@link System#in}, {@link System#out}, and
* {@link System#err} streams at run time. We want a fresh set of objects, so that any buffers
Expand All @@ -47,11 +58,14 @@
* This can be customized by calling {@link #setIn}, {@link #setOut}, and {@link #setErr} before the
* static analysis starts, i.e., in a {@link Feature#beforeAnalysis} method.
*/
public final class SystemInOutErrSupport {
public final class SystemInOutErrSupport implements InitialLayerOnlyImageSingleton {
private InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in));
private PrintStream out = newPrintStream(new FileOutputStream(FileDescriptor.out), System.getProperty("sun.stdout.encoding"));
private PrintStream err = newPrintStream(new FileOutputStream(FileDescriptor.err), System.getProperty("sun.stderr.encoding"));

@Platforms(Platform.HOSTED_ONLY.class) //
final AtomicBoolean isSealed = new AtomicBoolean(false);

/* Create `PrintStream` in the same way as `System.newPrintStream`. */
private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
if (enc != null) {
Expand All @@ -63,32 +77,66 @@ private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
return new PrintStream(new BufferedOutputStream(fos, 128), true);
}

public void seal() {
if (!isSealed.getPlain()) {
isSealed.set(true);
}
}

public void checkSealed() {
VMError.guarantee(!isSealed.get(), "SystemInOurErrorSupport is already sealed");
}

private static SystemInOutErrSupport singleton() {
return ImageSingletons.lookup(SystemInOutErrSupport.class);
}

@Fold
public InputStream in() {
seal();
return in;
}

@Platforms(Platform.HOSTED_ONLY.class)
public static void setIn(InputStream in) {
ImageSingletons.lookup(SystemInOutErrSupport.class).in = Objects.requireNonNull(in);
var support = singleton();
support.checkSealed();
support.in = Objects.requireNonNull(in);
}

@Fold
public PrintStream out() {
seal();
return out;
}

@Platforms(Platform.HOSTED_ONLY.class)
public static void setOut(PrintStream out) {
ImageSingletons.lookup(SystemInOutErrSupport.class).out = Objects.requireNonNull(out);
var support = singleton();
support.checkSealed();
support.out = Objects.requireNonNull(out);
}

@Fold
public PrintStream err() {
seal();
return err;
}

@Platforms(Platform.HOSTED_ONLY.class)
public static void setErr(PrintStream err) {
ImageSingletons.lookup(SystemInOutErrSupport.class).err = Objects.requireNonNull(err);
var support = singleton();
support.checkSealed();
support.err = Objects.requireNonNull(err);
}

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
}
}

@SuppressWarnings("unused")
class SystemInOutErrFeature implements Feature {
class SystemInOutErrFeature implements Feature, FeatureSingleton {
/* Dummy for backward compatibility. */
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@

import com.oracle.graal.pointsto.BigBang;
import com.oracle.graal.pointsto.ObjectScanner;
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
import com.oracle.graal.pointsto.meta.AnalysisField;
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
Expand Down Expand Up @@ -293,6 +294,15 @@ public void registerObjectReplacer(Function<Object, Object> replacer) {
getUniverse().registerObjectReplacer(replacer);
}

/**
* Register an object replacer which may return an ImageHeapConstant. Note only one replacer
* can be triggered for a given object; otherwise an error will be thrown. Too, if the
* object should not be replaced then {@code null} should be returned.
*/
public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant> replacer) {
getUniverse().registerObjectToConstantReplacer(replacer);
}

/**
* Register a callback that is executed when an object of the specified type or any of its
* subtypes is marked as reachable.
Expand Down
Loading