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 @@ -2861,7 +2861,7 @@ protected ConstantNode appendConstant(JavaConstant constant) {
}

@Override
public <T extends ValueNode> T append(T v) {
public <T extends Node> T append(T v) {
assert !graph.trackNodeSourcePosition() || graph.currentNodeSourcePosition() != null || currentBlock == blockMap.getUnwindBlock() || currentBlock instanceof ExceptionDispatchBlock;
if (v.graph() != null) {
return v;
Expand All @@ -2873,7 +2873,7 @@ public <T extends ValueNode> T append(T v) {
return added;
}

private <T extends ValueNode> void updateLastInstruction(T v) {
private <T extends Node> void updateLastInstruction(T v) {
if (v instanceof FixedNode) {
FixedNode fixedNode = (FixedNode) v;
if (lastInstr != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.StampPair;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.BeginNode;
Expand Down Expand Up @@ -90,7 +91,7 @@ public interface GraphBuilderContext extends GraphBuilderTool {
*
* @param kind the kind to use when type checking this operation
* @param value the value to push to the stack. The value must already have been
* {@linkplain #append(ValueNode) appended}.
* {@linkplain #append(Node) appended}.
*/
void push(JavaKind kind, ValueNode value);

Expand Down Expand Up @@ -121,14 +122,24 @@ default ValueNode[] popArguments(int argSize) {
* type checking this operation.
* @return a node equivalent to {@code value} in the graph
*/
default <T extends ValueNode> T add(T value) {
default <T extends Node> T add(T value) {
if (value.graph() != null) {
assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
return value;
}
return setStateAfterIfNecessary(this, append(value));
}

/**
* Maybe performs canonicalization on the provided node. Either the result of the
* canonicalization, or the original node if canonicalization is not possible, is added to the
* graph and returned. Note that the return value can be null when canonicalization determines
* that the node can be deleted.
*/
default Node canonicalizeAndAdd(Node value) {
return add(value);
}

default ValueNode addNonNullCast(ValueNode value) {
AbstractPointerStamp valueStamp = (AbstractPointerStamp) value.stamp(NodeView.DEFAULT);
if (valueStamp.nonNull()) {
Expand Down Expand Up @@ -536,7 +547,7 @@ default void replacePluginWithException(GeneratedInvocationPlugin plugin, Resolv
throw GraalError.unimplementedParent(); // ExcludeFromJacocoGeneratedReport
}

static <T extends ValueNode> T setStateAfterIfNecessary(GraphBuilderContext b, T value) {
static <T extends Node> T setStateAfterIfNecessary(GraphBuilderContext b, T value) {
if (value instanceof StateSplit) {
StateSplit stateSplit = (StateSplit) value;
FrameState oldState = stateSplit.stateAfter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
package org.graalvm.compiler.nodes.graphbuilderconf;

import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.spi.CoreProviders;
import org.graalvm.compiler.options.OptionValues;

Expand All @@ -43,7 +43,7 @@ public interface GraphBuilderTool extends CoreProviders {
* @param value the node to be added to the graph
* @return either the node added or an equivalent node
*/
<T extends ValueNode> T append(T value);
<T extends Node> T append(T value);

default Assumptions getAssumptions() {
return getGraph().getAssumptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.Node.ValueNumberable;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.java.FrameStateBuilder;
Expand Down Expand Up @@ -153,9 +154,9 @@ public <T extends ValueNode> T add(T node) {
return graph.add(changeToWord(node));
}

public <T extends ValueNode> T changeToWord(T node) {
if (wordTypes != null && wordTypes.isWord(node)) {
node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node)));
public <T extends Node> T changeToWord(T node) {
if (node instanceof ValueNode valueNode && wordTypes != null && wordTypes.isWord(valueNode)) {
valueNode.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(valueNode)));
}
return node;
}
Expand All @@ -170,7 +171,7 @@ public final JavaKind asKind(JavaType type) {
}

@Override
public <T extends ValueNode> T append(T node) {
public <T extends Node> T append(T node) {
if (node.graph() != null) {
return node;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.java.FrameStateBuilder;
import org.graalvm.compiler.nodes.AbstractBeginNode;
Expand Down Expand Up @@ -163,7 +164,7 @@ protected IntrinsicGraphBuilder(OptionValues options,
}
}

private <T extends ValueNode> void updateLastInstruction(T v) {
private <T extends Node> void updateLastInstruction(T v) {
if (v instanceof FixedNode) {
FixedNode fixedNode = (FixedNode) v;
if (lastInstr != null) {
Expand Down Expand Up @@ -222,7 +223,7 @@ protected void mergeUnwinds() {
}

@Override
public <T extends ValueNode> T append(T v) {
public <T extends Node> T append(T v) {
if (v.graph() != null) {
return v;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import org.graalvm.compiler.nodes.UnwindNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.WithExceptionNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
import org.graalvm.compiler.nodes.extended.AnchoringNode;
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
Expand Down Expand Up @@ -421,7 +422,7 @@ public IntrinsicContext getIntrinsic() {
}

@Override
public <T extends ValueNode> T append(T value) {
public <T extends Node> T append(T value) {
throw unimplementedOverride(); // ExcludeFromJacocoGeneratedReport
}

Expand Down Expand Up @@ -550,7 +551,7 @@ public void setStateAfter(StateSplit stateSplit) {

@SuppressWarnings("try")
@Override
public <T extends ValueNode> T append(T v) {
public <T extends Node> T append(T v) {
if (v.graph() != null) {
return v;
}
Expand All @@ -563,6 +564,21 @@ public <T extends ValueNode> T append(T v) {
}
}

@Override
public Node canonicalizeAndAdd(Node node) {
Node canonicalized = node;
if (canonicalized instanceof FixedNode fixedNode) {
canonicalized = canonicalizeFixedNode(methodScope, null, fixedNode);
} else if (canonicalized instanceof FloatingNode floatingNode) {
canonicalized = handleFloatingNodeBeforeAdd(methodScope, null, floatingNode);
}

if (canonicalized == null) {
return null;
}
return super.canonicalizeAndAdd(canonicalized);
}

private DebugCloseable withNodeSourcePosition() {
if (getGraph().trackNodeSourcePosition()) {
NodeSourcePosition callerBytecodePosition = methodScope.getCallerNodeSourcePosition();
Expand All @@ -573,7 +589,7 @@ private DebugCloseable withNodeSourcePosition() {
return null;
}

private <T extends ValueNode> void updateLastInstruction(T v) {
private <T extends Node> void updateLastInstruction(T v) {
if (v instanceof FixedNode) {
FixedNode fixedNode = (FixedNode) v;
if (lastInstr != null) {
Expand Down Expand Up @@ -721,7 +737,7 @@ public void setStateAfter(StateSplit sideEffect) {

@SuppressWarnings("try")
@Override
public <T extends ValueNode> T append(T v) {
public <T extends Node> T append(T v) {
if (v.graph() != null) {
return v;
}
Expand All @@ -744,7 +760,7 @@ private DebugCloseable withNodeSourcePosition() {
return null;
}

private <T extends ValueNode> void updateLastInstruction(T value) {
private <T extends Node> void updateLastInstruction(T value) {
if (value instanceof FixedWithNextNode) {
FixedWithNextNode fixed = (FixedWithNextNode) value;
graph.addBeforeFixed(insertBefore, fixed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

import java.lang.reflect.Proxy;

import org.graalvm.compiler.java.LambdaUtils;

import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
import com.oracle.svm.core.util.UserError;
Expand Down Expand Up @@ -159,9 +161,27 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
}
superResult = superResult.max(processInterfaces(clazz, memoize));

if (superResult == InitKind.BUILD_TIME && Proxy.isProxyClass(clazz)) {
forceInitializeHosted(clazz, "proxy classes with interfaces initialized at build time are also initialized at build time", false);
return InitKind.BUILD_TIME;
if (superResult == InitKind.BUILD_TIME && (Proxy.isProxyClass(clazz) || LambdaUtils.isLambdaType(metaAccess.lookupJavaType(clazz)))) {
/*
* To simplify class initialization configuration for proxy and lambda types,
* registering all of their implemented interfaces as "initialize at build time" is
* equivalent to registering the proxy/lambda type itself. This is safe because we know
* that proxy/lambda types themselves have no problematic code in the class initializer
* (they are generated classes).
*
* Note that we must look at all interfaces, including transitive dependencies.
*/
boolean allInterfacesSpecifiedAsBuildTime = true;
for (Class<?> iface : allInterfaces(clazz)) {
if (specifiedInitKindFor(iface) != InitKind.BUILD_TIME) {
allInterfacesSpecifiedAsBuildTime = false;
break;
}
}
if (allInterfacesSpecifiedAsBuildTime) {
forceInitializeHosted(clazz, "proxy/lambda classes with all interfaces explicitly marked as --initialize-at-build-time are also initialized at build time", false);
return InitKind.BUILD_TIME;
}
}

InitKind result = superResult.max(clazzResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static com.oracle.svm.hosted.classinitialization.InitKind.RUN_TIME;

import java.io.PrintWriter;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
Expand Down Expand Up @@ -125,14 +126,42 @@ private Object checkImageHeapInstance(Object obj) {
* means that the user cannot later manually register it as RERUN or RUN_TIME.
*/
if (obj != null && !classInitializationSupport.maybeInitializeAtBuildTime(obj.getClass())) {
String msg = "No instances of " + obj.getClass().getTypeName() + " are allowed in the image heap as this class should be initialized at image runtime.";
msg += classInitializationSupport.objectInstantiationTraceMessage(obj,
" To fix the issue mark " + obj.getClass().getTypeName() + " for build-time initialization with " +
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, obj.getClass().getTypeName(), "initialize-at-build-time") +
" or use the the information from the trace to find the culprit and " +
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, "<culprit>", "initialize-at-run-time") +
" to prevent its instantiation.\n");
throw new UnsupportedFeatureException(msg);
StringBuilder msg = new StringBuilder()
.append("No instances of ").append(obj.getClass().getTypeName()).append(" are allowed in the image heap as this class should be initialized at image runtime.");

String action = " To fix the issue mark " + obj.getClass().getTypeName() + " for build-time initialization with " +
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, obj.getClass().getTypeName(), "initialize-at-build-time") +
" or use the the information from the trace to find the culprit and " +
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, "<culprit>", "initialize-at-run-time") +
" to prevent its instantiation." + System.lineSeparator();
msg.append(classInitializationSupport.objectInstantiationTraceMessage(obj, action));

if (!ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
msg.append(System.lineSeparator())
.append("If you see this error while migrating to a newer GraalVM release, please note that the class initialization strategy has changed in GraalVM for JDK 21.")
.append(" All classes can now be used at image build time. However, only classes explicitly marked as --initialize-at-build-time are allowed to be in the image heap.")
.append(" This rule is now strictly enforced, i.e., the problem might be solvable by registering the reported type as --initialize-at-build-time.");
}

String proxyOrLambda = null;
if (Proxy.isProxyClass(obj.getClass())) {
proxyOrLambda = "Proxy";
} else if (obj.getClass().getName().contains(LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING)) {
proxyOrLambda = "Lambda";
}
if (proxyOrLambda != null) {
msg.append(System.lineSeparator())
.append("For ").append(proxyOrLambda).append(" classes, it is also sufficient to register all interfaces that the class implements as --initialize-at-build-time. ")
.append(" The interfaces of this ").append(proxyOrLambda).append(" class are: [");
String sep = "";
for (var iface : ClassInitializationSupport.allInterfaces(obj.getClass())) {
msg.append(sep).append(iface.getTypeName());
sep = ", ";
}
msg.append("].");
}

throw new UnsupportedFeatureException(msg.toString());
}
return obj;
}
Expand Down Expand Up @@ -205,7 +234,7 @@ public void afterAnalysis(AfterAnalysisAccess a) {
.filter(c -> c.getClassLoader() != null && c.getClassLoader() != ClassLoader.getPlatformClassLoader())
.filter(c -> classInitializationSupport.specifiedInitKindFor(c) == null)
.map(Class::getTypeName)
.filter(name -> !LambdaUtils.isLambdaName(name))
.filter(name -> !name.contains(LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING))
.collect(Collectors.toList());
if (!unspecifiedClasses.isEmpty()) {
System.err.println("The following classes have unspecified initialization policy:" + System.lineSeparator() + String.join(System.lineSeparator(), unspecifiedClasses));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import org.graalvm.collections.EconomicSet;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking;
Expand Down Expand Up @@ -305,4 +306,18 @@ static String getTraceString(StackTraceElement[] trace) {
abstract boolean checkDelayedInitialization();

abstract void doLateInitialization(AnalysisUniverse universe, AnalysisMetaAccess aMetaAccess);

public static EconomicSet<Class<?>> allInterfaces(Class<?> clazz) {
EconomicSet<Class<?>> result = EconomicSet.create();
addAllInterfaces(clazz, result);
return result;
}

private static void addAllInterfaces(Class<?> clazz, EconomicSet<Class<?>> result) {
for (var interf : clazz.getInterfaces()) {
if (result.add(interf)) {
addAllInterfaces(interf, result);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@

import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.image.DisallowedImageHeapObjects;
import com.oracle.svm.core.jdk.management.ManagementFeature;
import com.oracle.svm.core.jdk.management.ManagementSupport;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.hosted.FeatureImpl;
import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions;
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
Expand Down Expand Up @@ -168,18 +168,11 @@ private void checkDisallowedMBeanObjects(Object original) {
}

private RuntimeException error(String msg, Object obj, String initializerAction) {
String suffix = "";
if (!ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
suffix = System.lineSeparator() +
"If you see this error while migrating to a newer GraalVM release, please note that the class initialization strategy has changed in GraalVM for JDK 21." +
" All classes can now be used at image build time. However, only classes explicitly marked as --initialize-at-built-time are allowed to be in the image heap." +
" This rule is now strictly enforced, i.e., the problem might be solvable by registering the reported type as --initialize-at-built-time.";
}
throw new UnsupportedFeatureException(msg + " " + classInitialization.objectInstantiationTraceMessage(obj, initializerAction) + " " +
"The object was probably created by a class initializer and is reachable from a static field. " +
"You can request class initialization at image runtime by using the option " +
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, "<class-name>", "initialize-at-run-time") + ". " +
"Or you can write your own initialization methods and call them explicitly from your main entry point." + suffix);
"Or you can write your own initialization methods and call them explicitly from your main entry point.");
}

private static boolean search(byte[] haystack, byte[] needle) {
Expand Down
Loading