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,9 +122,10 @@ public class SubstrateAllocationSnippets extends AllocationSnippets {
public static final LocationIdentity[] GC_LOCATIONS = new LocationIdentity[]{TLAB_TOP_IDENTITY, TLAB_END_IDENTITY, IdentityHashCodeSupport.IDENTITY_HASHCODE_SALT_LOCATION};

private static final SubstrateForeignCallDescriptor NEW_MULTI_ARRAY = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class, "newMultiArrayStub", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor INSTANCE_HUB_ERROR = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class, "instanceHubErrorStub", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class,
"slowPathHubOrUnsafeInstantiationError", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor ARRAY_HUB_ERROR = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class, "arrayHubErrorStub", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{NEW_MULTI_ARRAY, INSTANCE_HUB_ERROR, ARRAY_HUB_ERROR};
private static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{NEW_MULTI_ARRAY, SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR, ARRAY_HUB_ERROR};

public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) {
foreignCalls.register(FOREIGN_CALLS);
Expand Down Expand Up @@ -272,12 +273,12 @@ protected Object newmultiarray(DynamicHub hub, @ConstantParameter int rank, @Con
public DynamicHub validateNewInstanceClass(DynamicHub hub) {
if (probability(EXTREMELY_FAST_PATH_PROBABILITY, hub != null)) {
DynamicHub nonNullHub = (DynamicHub) PiNode.piCastNonNull(hub, SnippetAnchorNode.anchor());
if (probability(EXTREMELY_FAST_PATH_PROBABILITY, nonNullHub.canUnsafeInstantiateAsInstance())) {
if (probability(EXTREMELY_FAST_PATH_PROBABILITY, nonNullHub.canUnsafeInstantiateAsInstanceFastPath())) {
return nonNullHub;
}
}
callInstanceHubErrorWithExceptionStub(INSTANCE_HUB_ERROR, DynamicHub.toClass(hub));
throw UnreachableNode.unreachable();
DynamicHub slowPathStub = slowPathHubOrUnsafeInstantiationErrorStub(SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR, DynamicHub.toClass(hub));
return (DynamicHub) PiNode.piCastNonNull(slowPathStub, SnippetAnchorNode.anchor());
}

/** Foreign call: {@link #NEW_MULTI_ARRAY}. */
Expand Down Expand Up @@ -308,25 +309,28 @@ private static Object newMultiArrayRecursion(DynamicHub hub, int rank, Word dime
}

@NodeIntrinsic(value = ForeignCallWithExceptionNode.class)
private static native void callInstanceHubErrorWithExceptionStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> hub);
private static native DynamicHub slowPathHubOrUnsafeInstantiationErrorStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> hub);

/** Foreign call: {@link #INSTANCE_HUB_ERROR}. */
/** Foreign call: {@link #SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR}. */
@SubstrateForeignCallTarget(stubCallingConvention = true)
private static void instanceHubErrorStub(DynamicHub hub) throws InstantiationException {
private static DynamicHub slowPathHubOrUnsafeInstantiationError(DynamicHub hub) throws InstantiationException {
if (hub == null) {
throw new NullPointerException("Allocation type is null.");
} else if (!hub.isInstanceClass() || LayoutEncoding.isSpecial(hub.getLayoutEncoding())) {
throw new InstantiationException("Can only allocate instance objects for concrete classes.");
} else if (!hub.canUnsafeInstantiateAsInstance()) {
if (MissingRegistrationUtils.throwMissingRegistrationErrors()) {
MissingReflectionRegistrationUtils.forClass(hub.getTypeName());
}
throw new IllegalArgumentException("Type " + DynamicHub.toClass(hub).getTypeName() + " is instantiated reflectively but was never registered." +
" Register the type by adding \"unsafeAllocated\" for the type in " + ConfigurationFile.REFLECTION.getFileName() + ".");
throw new InstantiationException("Can only allocate instance objects for concrete classes: " + DynamicHub.toClass(hub).getTypeName());
} else if (LayoutEncoding.isHybrid(hub.getLayoutEncoding())) {
throw new InstantiationException("Cannot allocate objects of special hybrid types.");
throw new InstantiationException("Cannot allocate objects of special hybrid types: " + DynamicHub.toClass(hub).getTypeName());
} else {
throw VMError.shouldNotReachHereUnexpectedInput(hub); // ExcludeFromJacocoGeneratedReport
if (hub.canUnsafeInstantiateAsInstanceSlowPath()) {
hub.getCompanion().setUnsafeAllocate();
return hub;
} else {
if (MissingRegistrationUtils.throwMissingRegistrationErrors()) {
MissingReflectionRegistrationUtils.forUnsafeAllocation(hub.getTypeName());
}
throw new IllegalArgumentException("Type " + DynamicHub.toClass(hub).getTypeName() + " is instantiated reflectively but was never registered." +
" Register the type by adding \"unsafeAllocated\" for the type in " + ConfigurationFile.REFLECTION.getFileName() + ".");
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public static ClassForNameSupport singleton() {

/** The map used to collect registered classes. */
private final EconomicMap<String, ConditionalRuntimeValue<Object>> knownClasses = ImageHeapMap.create();
/** The map used to collect unsafe allocated classes. */
private final EconomicMap<Class<?>, RuntimeConditionSet> unsafeInstantiatedClasses = ImageHeapMap.create();

private static final Object NEGATIVE_QUERY = new Object();

Expand Down Expand Up @@ -138,6 +140,16 @@ public void registerNegativeQuery(ConfigurationCondition condition, String class
updateCondition(condition, className, NEGATIVE_QUERY);
}

@Platforms(Platform.HOSTED_ONLY.class)
public void registerUnsafeAllocated(ConfigurationCondition condition, Class<?> clazz) {
if (!clazz.isArray()) {
var conditionSet = unsafeInstantiatedClasses.putIfAbsent(clazz, RuntimeConditionSet.createHosted(condition));
if (conditionSet != null) {
conditionSet.addCondition(condition);
}
}
}

private void updateCondition(ConfigurationCondition condition, String className, Object value) {
synchronized (knownClasses) {
var runtimeConditions = knownClasses.putIfAbsent(className, new ConditionalRuntimeValue<>(RuntimeConditionSet.createHosted(condition), value));
Expand Down Expand Up @@ -213,4 +225,13 @@ public RuntimeConditionSet getConditionFor(Class<?> jClass) {
return conditionalClass.getConditions();
}
}

/**
* Checks whether {@code hub} can be instantiated with {@code Unsafe.allocateInstance}. Note
* that arrays can't be instantiated and this function will always return false for array types.
*/
public boolean canUnsafeInstantiateAsInstance(DynamicHub hub) {
var conditionSet = unsafeInstantiatedClasses.get(DynamicHub.toClass(hub));
return conditionSet != null && conditionSet.satisfied();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -312,10 +312,6 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ

/** Indicates whether the type has been discovered as instantiated by the static analysis. */
private static final int IS_INSTANTIATED_BIT = 0;
/** Can this class be instantiated as an instance. */
private static final int CAN_UNSAFE_INSTANTIATE_AS_INSTANCE_BIT = 1;

private static final int IS_REGISTERED_FOR_SERIALIZATION = 2;

/**
* The {@link Modifier modifiers} of this class.
Expand Down Expand Up @@ -492,8 +488,7 @@ public void setClassInitializationInfo(ClassInitializationInfo classInitializati

@Platforms(Platform.HOSTED_ONLY.class)
public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex,
boolean isInstantiated, boolean canUnsafeInstantiateAsInstance) {
assert !(!isInstantiated && canUnsafeInstantiateAsInstance);
boolean isInstantiated) {
VMError.guarantee(monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name);
VMError.guarantee(identityHashOffset == (char) identityHashOffset, "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name);

Expand All @@ -505,8 +500,7 @@ public void setSharedData(int layoutEncoding, int monitorOffset, int identityHas
throw VMError.shouldNotReachHere("Reference map index not within integer range, need to switch field from int to long");
}
this.referenceMapIndex = (int) referenceMapIndex;
this.additionalFlags = NumUtil.safeToUByte(makeFlag(IS_INSTANTIATED_BIT, isInstantiated) |
makeFlag(CAN_UNSAFE_INSTANTIATE_AS_INSTANCE_BIT, canUnsafeInstantiateAsInstance));
this.additionalFlags = NumUtil.safeToUByte(makeFlag(IS_INSTANTIATED_BIT, isInstantiated));
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand Down Expand Up @@ -747,8 +741,17 @@ public boolean isInstantiated() {
return isFlagSet(additionalFlags, IS_INSTANTIATED_BIT);
}

public boolean canUnsafeInstantiateAsInstance() {
return isFlagSet(additionalFlags, CAN_UNSAFE_INSTANTIATE_AS_INSTANCE_BIT);
public boolean canUnsafeInstantiateAsInstanceFastPath() {
return companion.canUnsafeAllocate();
}

public boolean canUnsafeInstantiateAsInstanceSlowPath() {
if (ClassForNameSupport.singleton().canUnsafeInstantiateAsInstance(this)) {
companion.setUnsafeAllocate();
return true;
} else {
return false;
}
}

public boolean isProxyClass() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public final class DynamicHubCompanion {
private Constructor<?> cachedConstructor;
private Class<?> newInstanceCallerCache;
private Object jfrEventConfiguration;
private boolean canUnsafeAllocate;

@Platforms(Platform.HOSTED_ONLY.class)
DynamicHubCompanion(Class<?> hostedJavaClass, ClassLoader classLoader) {
Expand Down Expand Up @@ -141,4 +142,12 @@ public void setJfrEventConfiguration(Object configuration) {
public Object getJfrEventConfiguration() {
return jfrEventConfiguration;
}

public boolean canUnsafeAllocate() {
return canUnsafeAllocate;
}

public void setUnsafeAllocate() {
canUnsafeAllocate = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public static void forClass(String className) {
report(exception);
}

public static void forUnsafeAllocation(String className) {
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("unsafe instantiate class", className),
Class.class, null, className, null);
report(exception);
}

public static void forField(Class<?> declaringClass, String fieldName) {
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("access field",
declaringClass.getTypeName() + "#" + fieldName),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private static void registerFields(FieldIntrospection<?> introspection, BeforeAn

/* The partial evaluator allocates Node classes via Unsafe. */
AnalysisType nodeType = config.getMetaAccess().lookupJavaType(nodeClass.getJavaClass());
nodeType.registerInstantiatedCallback(unused -> nodeType.registerAsUnsafeAllocated("Graal node class"));
nodeType.registerInstantiatedCallback(unused -> config.registerAsUnsafeAllocated(nodeType));

Fields dataFields = nodeClass.getData();
registerFields(dataFields, config, "Graal node data field");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess;
import org.graalvm.nativeimage.hosted.FieldValueTransformer;
import org.graalvm.nativeimage.hosted.RuntimeReflection;
import org.graalvm.nativeimage.impl.ConfigurationCondition;

import com.oracle.graal.pointsto.BigBang;
import com.oracle.graal.pointsto.ObjectScanner;
Expand All @@ -69,6 +70,7 @@
import com.oracle.svm.core.annotate.Delete;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
import com.oracle.svm.core.hub.ClassForNameSupport;
import com.oracle.svm.core.meta.SharedField;
import com.oracle.svm.core.meta.SharedMethod;
import com.oracle.svm.core.meta.SharedType;
Expand Down Expand Up @@ -349,12 +351,15 @@ public static class BeforeAnalysisAccessImpl extends AnalysisAccessBase implemen
private final NativeLibraries nativeLibraries;
private final boolean concurrentReachabilityHandlers;
private final ReachabilityHandler reachabilityHandler;
private ClassForNameSupport classForNameSupport;

public BeforeAnalysisAccessImpl(FeatureHandler featureHandler, ImageClassLoader imageClassLoader, Inflation bb, NativeLibraries nativeLibraries, DebugContext debugContext) {
public BeforeAnalysisAccessImpl(FeatureHandler featureHandler, ImageClassLoader imageClassLoader, Inflation bb, NativeLibraries nativeLibraries,
DebugContext debugContext) {
super(featureHandler, imageClassLoader, bb, debugContext);
this.nativeLibraries = nativeLibraries;
this.concurrentReachabilityHandlers = SubstrateOptions.RunReachabilityHandlersConcurrently.getValue(bb.getOptions());
this.reachabilityHandler = concurrentReachabilityHandlers ? ConcurrentReachabilityHandler.singleton() : ReachabilityHandlerFeature.singleton();
this.classForNameSupport = ClassForNameSupport.singleton();
}

public NativeLibraries getNativeLibraries() {
Expand Down Expand Up @@ -397,6 +402,7 @@ public void registerAsUnsafeAllocated(AnalysisType aType) {
throw UserError.abort("Cannot register an abstract class as instantiated: " + aType.toJavaName(true));
}
aType.registerAsUnsafeAllocated("From feature");
classForNameSupport.registerUnsafeAllocated(ConfigurationCondition.alwaysTrue(), aType.getJavaClass());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import java.util.function.BiPredicate;
import java.util.function.Function;

import com.oracle.svm.core.interpreter.InterpreterSupport;
import org.graalvm.nativeimage.AnnotationAccess;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
Expand Down Expand Up @@ -93,6 +92,7 @@
import com.oracle.svm.core.hub.PredefinedClassesSupport;
import com.oracle.svm.core.hub.ReferenceType;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.interpreter.InterpreterSupport;
import com.oracle.svm.core.jdk.InternalVMMethod;
import com.oracle.svm.core.jdk.LambdaFormHiddenMethod;
import com.oracle.svm.core.option.HostedOptionKey;
Expand Down Expand Up @@ -360,7 +360,8 @@ public void onTypeInstantiated(BigBang bb, AnalysisType type) {

if (optionAllowUnsafeAllocationOfAllInstantiatedTypes != null) {
if (optionAllowUnsafeAllocationOfAllInstantiatedTypes) {
type.registerAsUnsafeAllocated("All types are registered as Unsafe allocated via option AllowUnsafeAllocationOfAllInstantiatedTypes");
type.registerAsUnsafeAllocated("All types are registered as Unsafe allocated via option -H:+AllowUnsafeAllocationOfAllInstantiatedTypes");
typeToHub.get(type).getCompanion().setUnsafeAllocate();
} else {
/*
* No default registration for unsafe allocation, setting the explicit option has
Expand All @@ -369,6 +370,7 @@ public void onTypeInstantiated(BigBang bb, AnalysisType type) {
}
} else if (!missingRegistrationSupport.reportMissingRegistrationErrors(type.getJavaClass())) {
type.registerAsUnsafeAllocated("Type is not listed as ThrowMissingRegistrationError and therefore registered as Unsafe allocated automatically for compatibility reasons");
typeToHub.get(type).getCompanion().setUnsafeAllocate();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,6 @@ private void buildHubs() {
hUniverse.hostVM().recordActivity();

int layoutHelper;
boolean canUnsafeInstantiateAsInstance = false;
int monitorOffset = 0;
int identityHashOffset = 0;
if (type.isInstanceClass()) {
Expand All @@ -879,10 +878,8 @@ private void buildHubs() {
JavaKind storageKind = hybridLayout.getArrayElementStorageKind();
boolean isObject = (storageKind == JavaKind.Object);
layoutHelper = LayoutEncoding.forHybrid(type, isObject, hybridLayout.getArrayBaseOffset(), ol.getArrayIndexShift(storageKind));
canUnsafeInstantiateAsInstance = type.wrapped.isUnsafeAllocated() && HybridLayout.canInstantiateAsInstance(type);
} else {
layoutHelper = LayoutEncoding.forPureInstance(type, ConfigurationValues.getObjectLayout().alignUp(instanceClass.getInstanceSize()));
canUnsafeInstantiateAsInstance = type.wrapped.isUnsafeAllocated();
}
monitorOffset = instanceClass.getMonitorFieldOffset();
identityHashOffset = instanceClass.getIdentityHashOffset();
Expand All @@ -909,7 +906,7 @@ private void buildHubs() {

DynamicHub hub = type.getHub();
hub.setSharedData(layoutHelper, monitorOffset, identityHashOffset,
referenceMapIndex, type.isInstantiated(), canUnsafeInstantiateAsInstance);
referenceMapIndex, type.isInstantiated());

if (SubstrateOptions.closedTypeWorld()) {
CFunctionPointer[] vtable = new CFunctionPointer[type.closedTypeWorldVTable.length];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
private AnalysisUniverse universe;
private final SubstrateAnnotationExtractor annotationExtractor;
private BeforeAnalysisAccessImpl analysisAccess;
private ClassForNameSupport classForNameSupport;
private final ClassForNameSupport classForNameSupport;

private boolean sealed;

Expand Down Expand Up @@ -256,7 +256,8 @@ private void registerClass(ConfigurationCondition condition, Class<?> clazz, boo
AnalysisType type = metaAccess.lookupJavaType(clazz);
type.registerAsReachable("Is registered for reflection.");
if (unsafeInstantiated) {
type.registerAsUnsafeAllocated("Is registered for reflection.");
type.registerAsUnsafeAllocated("Is registered via reflection metadata.");
classForNameSupport.registerUnsafeAllocated(condition, clazz);
}

if (allowForName) {
Expand Down