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 @@ -122,6 +122,8 @@ protected void verify(StructuredGraph graph, CoreProviders context) {
"org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidDumpUsagePhase.run",
"org.graalvm.compiler.hotspot.SymbolicSnippetEncoder.verifySnippetEncodeDecode",
"com.oracle.graal.pointsto.phases.InlineBeforeAnalysis.decodeGraph",
"com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport.decodeGraph",
"com.oracle.svm.hosted.classinitialization.SimulateClassInitializerAbortException.doAbort",
"org.graalvm.compiler.truffle.compiler.phases.inlining.CallTree.dumpBasic",
"org.graalvm.compiler.truffle.compiler.phases.inlining.GraphManager.peRoot"));

Expand Down
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases.
* (GR-45841) BellSoft added support for the JFR event ThreadCPULoad.
* (GR-45994) Removed the option `-H:EnableSignalAPI`. Please use the runtime option `EnableSignalHandling` if it is necessary to enable or disable signal handling explicitly.
* (GR-39406) Simulation of class initializer: Class initializer of classes that are not marked for initialization at image build time are simulated at image build time to avoid executing them at image run time.

## Version 23.0.0
* (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning.
Expand Down
34 changes: 26 additions & 8 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1397,7 +1397,11 @@ def cinterfacetutorial(args):

@mx.command(suite.name, 'clinittest', 'Runs the ')
def clinittest(args):
def build_and_test_clinittest_image(native_image, args=None):
def build_and_test_clinittest_images(native_image, args=None):
build_and_test_clinittest_image(native_image, args, True)
build_and_test_clinittest_image(native_image, args, False)

def build_and_test_clinittest_image(native_image, args, new_class_init_policy):
args = [] if args is None else args
test_cp = classpath('com.oracle.svm.test')
build_dir = join(svmbuild_dir(), 'clinittest')
Expand All @@ -1407,11 +1411,17 @@ def build_and_test_clinittest_image(native_image, args=None):
remove_tree(build_dir)
mkpath(build_dir)

if new_class_init_policy:
policy_args = ['-H:+UseNewExperimentalClassInitialization', '-H:+SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureNewPolicyFeature']
else:
policy_args = ['-H:-UseNewExperimentalClassInitialization', '-H:-SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureOldPolicyFeature']

# Build and run the example
native_image(
['-H:Path=' + build_dir, '-cp', test_cp, '-H:Class=com.oracle.svm.test.clinit.TestClassInitializationMustBeSafeEarly',
'-H:Features=com.oracle.svm.test.clinit.TestClassInitializationMustBeSafeEarlyFeature',
'-H:+PrintClassInitialization', '-H:Name=clinittest', '-H:+ReportExceptionStackTraces'] + args)
['-H:Path=' + build_dir, '-cp', test_cp, '-H:Class=com.oracle.svm.test.clinit.TestClassInitialization',
'-J--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED',
'-J-ea', '-J-esa',
'-H:+PrintClassInitialization', '-H:Name=clinittest', '-H:+ReportExceptionStackTraces'] + policy_args + args)
mx.run([join(build_dir, 'clinittest')])

# Check the reports for initialized classes
Expand All @@ -1425,9 +1435,17 @@ def checkLine(line, marker, init_kind, msg, wrongly_initialized_lines):
"Classes marked with " + marker + " must have init kind " + init_kind + " and message " + msg)]
with open(classes_file) as f:
for line in f:
checkLine(line, "MustBeDelayed", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
checkLine(line, "MustBeSafeEarly", "BUILD_TIME", "class proven as side-effect free before analysis", wrongly_initialized_lines)
checkLine(line, "MustBeSafeLate", "BUILD_TIME", "class proven as side-effect free after analysis", wrongly_initialized_lines)
if new_class_init_policy:
checkLine(line, "MustBeSafeEarly", "SIMULATED", "classes are initialized at run time by default", wrongly_initialized_lines)
checkLine(line, "MustBeSafeLate", "SIMULATED", "classes are initialized at run time by default", wrongly_initialized_lines)
checkLine(line, "MustBeSimulated", "SIMULATED", "classes are initialized at run time by default", wrongly_initialized_lines)
checkLine(line, "MustBeDelayed", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
else:
checkLine(line, "MustBeSafeEarly", "BUILD_TIME", "class proven as side-effect free before analysis", wrongly_initialized_lines)
checkLine(line, "MustBeSafeLate", "BUILD_TIME", "class proven as side-effect free after analysis", wrongly_initialized_lines)
checkLine(line, "MustBeSimulated", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
checkLine(line, "MustBeDelayed", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)

if len(wrongly_initialized_lines) > 0:
msg = ""
for (line, error) in wrongly_initialized_lines:
Expand All @@ -1439,7 +1457,7 @@ def checkLine(line, marker, init_kind, msg, wrongly_initialized_lines):

check_class_initialization(all_classes_file)

native_image_context_run(build_and_test_clinittest_image, args)
native_image_context_run(build_and_test_clinittest_images, args)


class SubstrateJvmFuncsFallbacksBuilder(mx.Project):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ protected final void scanField(AnalysisField field, JavaConstant receiver, ScanR
/* The value is not available yet. */
return;
}
JavaConstant fieldValue = bb.getConstantReflectionProvider().readFieldValue(field, receiver);
JavaConstant fieldValue = bb.getUniverse().getHeapScanner().readFieldValue(field, receiver);
if (fieldValue == null) {
StringBuilder backtrace = new StringBuilder();
buildObjectBacktrace(bb, reason, backtrace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import java.lang.reflect.Array;
import java.util.function.Consumer;

import org.graalvm.compiler.debug.GraalError;

import com.oracle.graal.pointsto.ObjectScanner;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.util.AnalysisError;
Expand Down Expand Up @@ -97,35 +95,10 @@ public JavaConstant readElementValue(int idx) {

@Override
public void setElement(int idx, JavaConstant value) {
/*
* Constants for sub-integer types are often just integer constants, i.e., we cannot rely on
* the JavaKind of the constant to match the type of the array.
*/
if (array instanceof boolean[] booleanArray) {
booleanArray[idx] = value.asInt() != 0;
} else if (array instanceof byte[] byteArray) {
byte v = (byte) value.asInt();
GraalError.guarantee(v == value.asInt(), "type mismatch");
byteArray[idx] = v;
} else if (array instanceof short[] shortArray) {
short v = (short) value.asInt();
GraalError.guarantee(v == value.asInt(), "type mismatch");
shortArray[idx] = v;
} else if (array instanceof char[] charArray) {
char v = (char) value.asInt();
GraalError.guarantee(v == value.asInt(), "type mismatch");
charArray[idx] = v;
} else if (array instanceof int[] intArray) {
intArray[idx] = value.asInt();
} else if (array instanceof long[] longArray) {
longArray[idx] = value.asLong();
} else if (array instanceof float[] floatArray) {
floatArray[idx] = value.asFloat();
} else if (array instanceof double[] doubleArray) {
doubleArray[idx] = value.asDouble();
} else {
throw AnalysisError.shouldNotReachHere("Unexpected array type: " + array.getClass());
if (value.getJavaKind() != type.getComponentType().getJavaKind()) {
throw AnalysisError.shouldNotReachHere("Cannot store value of kind " + value.getJavaKind() + " into primitive array of type " + type);
}
Array.set(array, idx, value.asBoxedPrimitive());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ void markTypeInstantiated(AnalysisType type, ScanReason reason) {
universe.getBigbang().registerTypeAsInHeap(type, reason);
}

JavaConstant createImageHeapConstant(JavaConstant constant, ScanReason reason) {
public JavaConstant createImageHeapConstant(JavaConstant constant, ScanReason reason) {
if (isNonNullObjectConstant(constant)) {
return getOrCreateImageHeapConstant(constant, reason);
}
Expand Down Expand Up @@ -490,6 +490,10 @@ protected ValueSupplier<JavaConstant> readHostedFieldValue(AnalysisField field,
return ValueSupplier.eagerValue(value);
}

public JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) {
return constantReflection.readFieldValue(field, receiver);
}

protected boolean skipScanning() {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ public enum UsageKind {
}

private final AnalysisFuture<Void> onTypeReachableTask;
private final AnalysisFuture<Void> initializeMetaDataTask;

/**
* Additional information that is only available for types that are marked as reachable.
*/
Expand Down Expand Up @@ -302,6 +304,7 @@ public AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKi

/* The registration task initializes the type. */
this.onTypeReachableTask = new AnalysisFuture<>(() -> universe.onTypeReachable(this), null);
this.initializeMetaDataTask = new AnalysisFuture<>(() -> universe.initializeMetaData(this), null);
this.typeData = new AnalysisFuture<>(() -> {
AnalysisError.guarantee(universe.getHeapScanner() != null, "Heap scanner is not available.");
return universe.getHeapScanner().computeTypeData(this);
Expand Down Expand Up @@ -689,6 +692,10 @@ public void ensureOnTypeReachableTaskDone() {
onTypeReachableTask.ensureDone();
}

public AnalysisFuture<Void> getInitializeMetaDataTask() {
return initializeMetaDataTask;
}

public boolean getReachabilityListenerNotified() {
return reachabilityListenerNotified;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,10 @@ public void onTypeReachable(AnalysisType type) {
}
}

public void initializeMetaData(AnalysisType type) {
bb.initializeMetaData(type);
}

public SubstitutionProcessor getSubstitutions() {
return substitutions;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class InlineBeforeAnalysisGraphDecoder extends PEGraphDecoder {

public class InlineBeforeAnalysisMethodScope extends PEMethodScope {

private final InlineBeforeAnalysisPolicy.AbstractPolicyScope policyScope;
public final InlineBeforeAnalysisPolicy.AbstractPolicyScope policyScope;

private boolean inliningAborted;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
import com.oracle.svm.hosted.cenum.CEnumCallWrapperSubstitutionProcessor;
import com.oracle.svm.hosted.classinitialization.ClassInitializationFeature;
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
import com.oracle.svm.hosted.code.CEntryPointCallStubSupport;
import com.oracle.svm.hosted.code.CEntryPointData;
import com.oracle.svm.hosted.code.CFunctionSubstitutionProcessor;
Expand Down Expand Up @@ -909,6 +910,8 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
originalProviders, platformConfig, classInitializationSupport, aMetaAccess);
aUniverse.hostVM().initializeProviders(aProviders);

ImageSingletons.add(SimulateClassInitializerSupport.class, ((SVMHost) aUniverse.hostVM()).createSimulateClassInitializerSupport(aMetaAccess));

bb = createBigBang(options, aUniverse, aMetaAccess, aProviders, analysisExecutor, loader.watchdog::recordActivity,
annotationSubstitutions);
aUniverse.setBigBang(bb);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess;
import com.oracle.graal.pointsto.meta.AnalysisField;
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
Expand Down Expand Up @@ -126,6 +127,7 @@
import com.oracle.svm.hosted.analysis.SVMParsingSupport;
import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions;
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
import com.oracle.svm.hosted.code.InliningUtilities;
import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
import com.oracle.svm.hosted.code.UninterruptibleAnnotationChecker;
Expand All @@ -135,6 +137,7 @@
import com.oracle.svm.hosted.meta.HostedUniverse;
import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase;
import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase;
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisGraphDecoderImpl;
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyImpl;
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils;
import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor;
Expand Down Expand Up @@ -306,7 +309,7 @@ public void onTypeReachable(AnalysisType analysisType) {
}

/* Decide when the type should be initialized. */
classInitializationSupport.maybeInitializeHosted(analysisType);
classInitializationSupport.maybeInitializeAtBuildTime(analysisType);

/*
* For reachable classes, registering class's package in appropriate class loader.
Expand Down Expand Up @@ -336,10 +339,10 @@ public void onTypeReachable(AnalysisType analysisType) {

@Override
public boolean isInitialized(AnalysisType type) {
boolean shouldInitializeAtRuntime = classInitializationSupport.shouldInitializeAtRuntime(type);
assert shouldInitializeAtRuntime || type.getWrapped().isInitialized() : "Types that are not marked for runtime initializations must have been initialized: " + type;
boolean initializedAtBuildTime = classInitializationSupport.maybeInitializeAtBuildTime(type);
assert !initializedAtBuildTime || type.getWrapped().isInitialized() : "Types that are not marked for runtime initializations must have been initialized: " + type;

return !shouldInitializeAtRuntime;
return initializedAtBuildTime;
}

private final boolean parseOnce = SubstrateOptions.parseOnce();
Expand Down Expand Up @@ -770,7 +773,7 @@ private InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy(MultiMethod.MultiM

@Override
public InlineBeforeAnalysisGraphDecoder createInlineBeforeAnalysisGraphDecoder(BigBang bb, AnalysisMethod method, StructuredGraph resultGraph) {
return new InlineBeforeAnalysisGraphDecoder(bb, inlineBeforeAnalysisPolicy(method.getMultiMethodKey()), resultGraph, bb.getProviders(method), null);
return new InlineBeforeAnalysisGraphDecoderImpl(bb, inlineBeforeAnalysisPolicy(method.getMultiMethodKey()), resultGraph, bb.getProviders(method));
}

public static class Options {
Expand Down Expand Up @@ -1032,4 +1035,8 @@ private static Class<?>[] extractAnnotationTypes(AnalysisField field, Class<?>[]
}
return annotationTypes.toArray(new Class<?>[0]);
}

public SimulateClassInitializerSupport createSimulateClassInitializerSupport(AnalysisMetaAccess aMetaAccess) {
return new SimulateClassInitializerSupport(aMetaAccess, this);
}
}
Loading