Skip to content

Commit 997ac79

Browse files
committed
Integrate unsafe allocation registration in ReflectionDataBuilder
1 parent 2a8a8d3 commit 997ac79

14 files changed

Lines changed: 175 additions & 116 deletions

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ public byte[] parseByteArray(int index, DynamicHub declaringType) {
301301
return decodeByteArray(reader);
302302
}
303303

304+
@Override
305+
public RuntimeDynamicAccessMetadata parseDynamicAccessMetadata(int index, int layerId) {
306+
UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(layerId), index, ByteArrayReader.supportsUnalignedMemoryAccess());
307+
boolean preserved = reader.getU1() == 1;
308+
return decodeDynamicAccessMetadata(reader, layerId, preserved);
309+
}
310+
304311
@Override
305312
public boolean isHiding(int modifiers) {
306313
return (modifiers & HIDING_FLAG_MASK) != 0;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeDynamicAccessMetadata.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ public class RuntimeDynamicAccessMetadata {
5959
private boolean satisfied;
6060
private volatile boolean preserved;
6161

62-
@Platforms(Platform.HOSTED_ONLY.class)
6362
public static RuntimeDynamicAccessMetadata emptySet(boolean preserved) {
6463
return new RuntimeDynamicAccessMetadata(new Object[0], preserved);
6564
}
@@ -147,6 +146,13 @@ public boolean satisfied() {
147146
return result;
148147
}
149148

149+
/*
150+
* Used in snippets, returns true only if the condition was already satisfied beforehand.
151+
*/
152+
public final boolean fastPathSatisfied() {
153+
return satisfied;
154+
}
155+
150156
public boolean isPreserved() {
151157
return preserved;
152158
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,6 @@ private static DynamicHub slowPathHubOrUnsafeInstantiationError(DynamicHub hub)
388388
throw new InstantiationException("Cannot allocate objects of special hybrid types: " + DynamicHub.toClass(hub).getTypeName());
389389
} else {
390390
if (hub.canUnsafeInstantiateAsInstanceSlowPath()) {
391-
hub.setCanUnsafeAllocate();
392391
return hub;
393392
} else {
394393
if (MissingRegistrationUtils.throwMissingRegistrationErrors()) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java

Lines changed: 3 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,12 @@
2727
import static com.oracle.svm.core.MissingRegistrationUtils.throwMissingRegistrationErrors;
2828
import static jdk.graal.compiler.options.OptionStability.EXPERIMENTAL;
2929

30-
import java.lang.reflect.Modifier;
3130
import java.util.ArrayList;
3231
import java.util.Collections;
3332
import java.util.HashMap;
3433
import java.util.List;
3534
import java.util.Map;
3635
import java.util.Objects;
37-
import java.util.Set;
3836
import java.util.function.BooleanSupplier;
3937
import java.util.function.Consumer;
4038

@@ -77,7 +75,6 @@ public final class ClassForNameSupport {
7775

7876
public static final String CLASSES_REGISTERED = "classes registered";
7977
public static final String CLASSES_REGISTERED_STATES = "classes registered states";
80-
public static final String UNSAFE_REGISTERED = "unsafe registered";
8178
public static final String RESPECTS_CLASS_LOADER = "respects class loader";
8279

8380
public static final class Options {
@@ -126,11 +123,6 @@ private static ClassForNameSupport[] layeredSingletons() {
126123
* respecting class loaders.
127124
*/
128125
private final EconomicMap<String, Throwable> knownExceptions;
129-
/**
130-
* The map used to collect unsafe allocated classes. This map only collects data for the current
131-
* layer.
132-
*/
133-
private final EconomicMap<Class<?>, RuntimeDynamicAccessMetadata> unsafeInstantiatedClasses;
134126

135127
/**
136128
* The map used to collect classes registered in previous layers. The boolean associated to each
@@ -143,19 +135,13 @@ private static ClassForNameSupport[] layeredSingletons() {
143135
@Platforms(HOSTED_ONLY.class) //
144136
private final Map<String, Boolean> previousLayerClasses;
145137

146-
/**
147-
* The set used to collect unsafe allocated classes in previous layers.
148-
*/
149-
@Platforms(HOSTED_ONLY.class) //
150-
private final Set<String> previousLayerUnsafe;
151-
152138
private static final Object NEGATIVE_QUERY = new Object();
153139

154140
public ClassForNameSupport() {
155-
this(Map.of(), Set.of(), respectClassLoader());
141+
this(Map.of(), respectClassLoader());
156142
}
157143

158-
public ClassForNameSupport(Map<String, Boolean> previousLayerClasses, Set<String> previousLayerUnsafe, boolean respectsClassLoader) {
144+
public ClassForNameSupport(Map<String, Boolean> previousLayerClasses, boolean respectsClassLoader) {
159145
if (respectsClassLoader) {
160146
knownClasses = null;
161147
knownClassNames = ImageHeapMap.createNonLayeredMap();
@@ -165,9 +151,7 @@ public ClassForNameSupport(Map<String, Boolean> previousLayerClasses, Set<String
165151
knownClassNames = null;
166152
knownExceptions = null;
167153
}
168-
unsafeInstantiatedClasses = ImageHeapMap.createNonLayeredMap();
169154
this.previousLayerClasses = previousLayerClasses;
170-
this.previousLayerUnsafe = previousLayerUnsafe;
171155
}
172156

173157
@Fold
@@ -298,22 +282,6 @@ private void registerKnownClassName(AccessCondition condition, String className,
298282
}
299283
}
300284

301-
@Platforms(Platform.HOSTED_ONLY.class)
302-
public void registerUnsafeAllocated(AccessCondition condition, Class<?> clazz, boolean preserved) {
303-
if (!clazz.isArray() && !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {
304-
/* Otherwise, UNSAFE.allocateInstance results in InstantiationException */
305-
if (!previousLayerUnsafe.contains(clazz.getName())) {
306-
var conditionSet = unsafeInstantiatedClasses.putIfAbsent(clazz, RuntimeDynamicAccessMetadata.createHosted(condition, preserved));
307-
if (conditionSet != null) {
308-
conditionSet.addCondition(condition);
309-
if (!preserved) {
310-
conditionSet.setNotPreserved();
311-
}
312-
}
313-
}
314-
}
315-
}
316-
317285
private void updateCondition(AccessCondition condition, String className, Object value) {
318286
synchronized (knownClasses) {
319287
var cond = new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.createHosted(condition, false), value);
@@ -469,17 +437,6 @@ public static boolean isPreserved(Class<?> jClass) {
469437
return false;
470438
}
471439

472-
public static boolean isUnsafeAllocatedPreserved(Class<?> jClass) {
473-
Objects.requireNonNull(jClass);
474-
for (var singleton : layeredSingletons()) {
475-
RuntimeDynamicAccessMetadata dynamicAccessMetadata = singleton.unsafeInstantiatedClasses.get(jClass);
476-
if (dynamicAccessMetadata != null) {
477-
return dynamicAccessMetadata.isPreserved();
478-
}
479-
}
480-
return false;
481-
}
482-
483440
public static boolean isRegisteredClass(String className) {
484441
if (!ClassNameSupport.isValidReflectionName(className)) {
485442
return true;
@@ -530,25 +487,6 @@ public static Throwable getSavedException(String className) {
530487
return exception;
531488
}
532489

533-
/**
534-
* Checks whether {@code hub} can be instantiated with {@code Unsafe.allocateInstance}. Note
535-
* that arrays can't be instantiated and this function will always return false for array types.
536-
*/
537-
public static boolean canUnsafeInstantiateAsInstance(DynamicHub hub) {
538-
Class<?> clazz = DynamicHub.toClass(hub);
539-
RuntimeDynamicAccessMetadata dynamicAccessMetadata = null;
540-
for (var singleton : layeredSingletons()) {
541-
dynamicAccessMetadata = singleton.unsafeInstantiatedClasses.get(clazz);
542-
if (dynamicAccessMetadata != null) {
543-
break;
544-
}
545-
}
546-
if (dynamicAccessMetadata != null) {
547-
return dynamicAccessMetadata.satisfied();
548-
}
549-
return false;
550-
}
551-
552490
static class LayeredCallbacks extends SingletonLayeredCallbacksSupplier {
553491
@Override
554492
public LayeredCallbacksSingletonTrait getLayeredCallbacksTrait() {
@@ -558,7 +496,6 @@ public LayeredCallbacksSingletonTrait getLayeredCallbacksTrait() {
558496
public LayeredPersistFlags doPersist(ImageSingletonWriter writer, ClassForNameSupport singleton) {
559497
List<String> classNames = new ArrayList<>();
560498
List<Boolean> classStates = new ArrayList<>();
561-
EconomicSet<String> unsafeNames = EconomicSet.create(singleton.previousLayerUnsafe);
562499

563500
var cursor = singleton.knownClasses.getEntries();
564501
while (cursor.advance()) {
@@ -579,11 +516,8 @@ public LayeredPersistFlags doPersist(ImageSingletonWriter writer, ClassForNameSu
579516
}
580517
}
581518

582-
singleton.unsafeInstantiatedClasses.getKeys().iterator().forEachRemaining(c -> unsafeNames.add(c.getName()));
583-
584519
writer.writeStringList(CLASSES_REGISTERED, classNames);
585520
writer.writeBoolList(CLASSES_REGISTERED_STATES, classStates);
586-
writer.writeStringList(UNSAFE_REGISTERED, unsafeNames.toList());
587521
/*
588522
* The option is not accessible when the singleton is loaded, so the boolean
589523
* needs to be persisted.
@@ -612,10 +546,9 @@ public ClassForNameSupport createFromLoader(ImageSingletonLoader loader) {
612546
previousLayerClasses.put(previousLayerClassKeys.get(i), previousLayerClassStates.get(i));
613547
}
614548

615-
Set<String> previousLayerUnsafe = Set.copyOf(loader.readStringList(UNSAFE_REGISTERED));
616549
boolean respectsClassLoader = loader.readInt(RESPECTS_CLASS_LOADER) == 1;
617550

618-
return new ClassForNameSupport(Collections.unmodifiableMap(previousLayerClasses), previousLayerUnsafe, respectsClassLoader);
551+
return new ClassForNameSupport(Collections.unmodifiableMap(previousLayerClasses), respectsClassLoader);
619552
}
620553
}
621554
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@
8585
import java.util.function.BiFunction;
8686
import java.util.function.IntFunction;
8787

88-
import com.oracle.svm.shared.singletons.MultiLayeredImageSingleton;
8988
import org.graalvm.collections.EconomicSet;
9089
import org.graalvm.nativeimage.AnnotationAccess;
9190
import org.graalvm.nativeimage.ImageSingletons;
9291
import org.graalvm.nativeimage.Platform;
9392
import org.graalvm.nativeimage.Platforms;
93+
import org.graalvm.nativeimage.dynamicaccess.AccessCondition;
9494
import org.graalvm.nativeimage.impl.ClassLoadingSupport;
9595
import org.graalvm.nativeimage.impl.InternalPlatform.NATIVE_ONLY;
9696

@@ -142,6 +142,7 @@
142142
import com.oracle.svm.core.util.BasedOnJDKFile;
143143
import com.oracle.svm.core.util.LazyFinalReference;
144144
import com.oracle.svm.guest.staging.Uninterruptible;
145+
import com.oracle.svm.shared.singletons.MultiLayeredImageSingleton;
145146
import com.oracle.svm.shared.util.VMError;
146147
import com.oracle.svm.util.AnnotationUtil;
147148
import com.oracle.svm.util.GuestAccess;
@@ -518,7 +519,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
518519
DynamicHubCompanion companion = DynamicHubCompanion.createAtRuntime(module, superHub, sourceFileName, modifiers, classLoader, simpleBinaryName, declaringClass, signature, info);
519520

520521
/* Always allow unsafe allocation for classes that were loaded at run-time. */
521-
companion.canUnsafeAllocate = true;
522+
companion.canUnsafeAllocate = RuntimeDynamicAccessMetadata.emptySet(false);
522523
companion.classInitializationInfo = ClassInitializationInfo.forRuntimeLoadedClass(false, hasClassInitializer);
523524
byte additionalFlags = NumUtil.safeToUByte((companion.additionalFlags & 0xff) | makeFlag(ADDITIONAL_FLAGS_INSTANTIATED_BIT, true));
524525
writeByte(companion, dynamicHubOffsets.getCompanionAdditionalFlagsOffset(), additionalFlags);
@@ -800,9 +801,10 @@ private DynamicHubMetadata hubMetadata() {
800801
}
801802

802803
@Platforms(Platform.HOSTED_ONLY.class)
803-
public void setReflectionMetadata(int fieldsEncodingIndex, int methodsEncodingIndex, int constructorsEncodingIndex, int recordComponentsEncodingIndex, int classFlags) {
804+
public void setReflectionMetadata(int fieldsEncodingIndex, int methodsEncodingIndex, int constructorsEncodingIndex, int recordComponentsEncodingIndex, int unsafeAllocationIndex, int classFlags) {
804805
assert companion.reflectionMetadata == null;
805-
ImageReflectionMetadata reflectionMetadata = new ImageReflectionMetadata(fieldsEncodingIndex, methodsEncodingIndex, constructorsEncodingIndex, recordComponentsEncodingIndex, classFlags);
806+
ImageReflectionMetadata reflectionMetadata = new ImageReflectionMetadata(fieldsEncodingIndex, methodsEncodingIndex, constructorsEncodingIndex, recordComponentsEncodingIndex,
807+
unsafeAllocationIndex, classFlags);
806808
if (ImageLayerBuildingSupport.buildingImageLayer()) {
807809
LayeredReflectionMetadataSingleton.currentLayer().setReflectionMetadata(this, reflectionMetadata);
808810
} else {
@@ -1058,24 +1060,40 @@ public boolean isInstantiated() {
10581060
}
10591061

10601062
public boolean canUnsafeInstantiateAsInstanceFastPath() {
1061-
return canUnsafeAllocate();
1063+
return companion.canUnsafeAllocate != null && companion.canUnsafeAllocate.fastPathSatisfied();
10621064
}
10631065

10641066
public boolean canUnsafeInstantiateAsInstanceSlowPath() {
1065-
if (ClassForNameSupport.canUnsafeInstantiateAsInstance(this)) {
1066-
setCanUnsafeAllocate();
1067-
return true;
1068-
} else {
1069-
return false;
1067+
RuntimeDynamicAccessMetadata canUnsafeAllocate = canUnsafeAllocate();
1068+
return canUnsafeAllocate != null && canUnsafeAllocate.satisfied();
1069+
}
1070+
1071+
private RuntimeDynamicAccessMetadata canUnsafeAllocate() {
1072+
if (companion.canUnsafeAllocate == null) {
1073+
RuntimeDynamicAccessMetadata unsafeAllocationMetadata = null;
1074+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
1075+
for (var reflectionMetadata : LayeredReflectionMetadataSingleton.singletons()) {
1076+
if (reflectionMetadata.getReflectionMetadata(this).unsafeAllocatedIndex != NO_DATA) {
1077+
unsafeAllocationMetadata = reflectionMetadata.getReflectionMetadata(this).getUnsafeAllocationMetadata(this, layerId);
1078+
break;
1079+
}
1080+
}
1081+
} else {
1082+
unsafeAllocationMetadata = reflectionMetadata().getUnsafeAllocationMetadata(this, layerId);
1083+
}
1084+
companion.canUnsafeAllocate = unsafeAllocationMetadata;
10701085
}
1071-
}
1072-
1073-
public boolean canUnsafeAllocate() {
10741086
return companion.canUnsafeAllocate;
10751087
}
10761088

1089+
@Platforms(Platform.HOSTED_ONLY.class)
10771090
public void setCanUnsafeAllocate() {
1078-
companion.canUnsafeAllocate = true;
1091+
companion.canUnsafeAllocate = RuntimeDynamicAccessMetadata.createHosted(AccessCondition.unconditional(), false);
1092+
}
1093+
1094+
public boolean isPreservedForUnsafeAllocation() {
1095+
RuntimeDynamicAccessMetadata canUnsafeAllocate = canUnsafeAllocate();
1096+
return canUnsafeAllocate != null && canUnsafeAllocate.isPreserved();
10791097
}
10801098

10811099
public boolean isProxyClass() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubCompanion.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import com.oracle.svm.core.BuildPhaseProvider;
3636
import com.oracle.svm.core.classinitialization.ClassInitializationInfo;
37+
import com.oracle.svm.core.configure.RuntimeDynamicAccessMetadata;
3738
import com.oracle.svm.core.heap.UnknownObjectField;
3839
import com.oracle.svm.core.heap.UnknownPrimitiveField;
3940
import com.oracle.svm.core.hub.RuntimeClassLoading.ClassDefinitionInfo;
@@ -155,7 +156,7 @@ public final class DynamicHubCompanion {
155156
Target_java_lang_Class_AnnotationData annotationData;
156157
Constructor<?> cachedConstructor;
157158
Object jfrEventConfiguration;
158-
@Stable boolean canUnsafeAllocate;
159+
@Stable RuntimeDynamicAccessMetadata canUnsafeAllocate;
159160
Object classData;
160161

161162
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ImageReflectionMetadata.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.graalvm.nativeimage.ImageSingletons;
3535

3636
import com.oracle.svm.core.BuildPhaseProvider;
37+
import com.oracle.svm.core.configure.RuntimeDynamicAccessMetadata;
3738
import com.oracle.svm.core.heap.UnknownPrimitiveField;
3839
import com.oracle.svm.core.reflect.RuntimeMetadataDecoder;
3940

@@ -55,14 +56,18 @@ public final class ImageReflectionMetadata implements ReflectionMetadata {
5556
@UnknownPrimitiveField(availability = BuildPhaseProvider.CompileQueueFinished.class)//
5657
final int recordComponentsEncodingIndex;
5758

59+
@UnknownPrimitiveField(availability = BuildPhaseProvider.CompileQueueFinished.class)//
60+
final int unsafeAllocatedIndex;
61+
5862
@UnknownPrimitiveField(availability = BuildPhaseProvider.CompileQueueFinished.class)//
5963
final int classFlags;
6064

61-
ImageReflectionMetadata(int fieldsEncodingIndex, int methodsEncodingIndex, int constructorsEncodingIndex, int recordComponentsEncodingIndex, int classFlags) {
65+
ImageReflectionMetadata(int fieldsEncodingIndex, int methodsEncodingIndex, int constructorsEncodingIndex, int recordComponentsEncodingIndex, int unsafeAllocatedIndex, int classFlags) {
6266
this.fieldsEncodingIndex = fieldsEncodingIndex;
6367
this.methodsEncodingIndex = methodsEncodingIndex;
6468
this.constructorsEncodingIndex = constructorsEncodingIndex;
6569
this.recordComponentsEncodingIndex = recordComponentsEncodingIndex;
70+
this.unsafeAllocatedIndex = unsafeAllocatedIndex;
6671
this.classFlags = classFlags;
6772
}
6873

@@ -103,4 +108,12 @@ public RecordComponent[] getRecordComponents(DynamicHub declaringClass, int laye
103108
}
104109
return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseRecordComponents(declaringClass, recordComponentsEncodingIndex, layerNum);
105110
}
111+
112+
@Override
113+
public RuntimeDynamicAccessMetadata getUnsafeAllocationMetadata(DynamicHub dynamicHub, int layerNum) {
114+
if (unsafeAllocatedIndex == NO_DATA) {
115+
return null;
116+
}
117+
return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseDynamicAccessMetadata(unsafeAllocatedIndex, layerNum);
118+
}
106119
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ReflectionMetadata.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import java.lang.reflect.Method;
3030
import java.lang.reflect.RecordComponent;
3131

32+
import com.oracle.svm.core.configure.RuntimeDynamicAccessMetadata;
33+
3234
interface ReflectionMetadata {
3335
int getClassFlags();
3436

@@ -39,4 +41,6 @@ interface ReflectionMetadata {
3941
Constructor<?>[] getDeclaredConstructors(DynamicHub declaringClass, boolean publicOnly, int layerNum);
4042

4143
RecordComponent[] getRecordComponents(DynamicHub dynamicHub, int layerNum);
44+
45+
RuntimeDynamicAccessMetadata getUnsafeAllocationMetadata(DynamicHub dynamicHub, int layerNum);
4246
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeReflectionMetadata.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.oracle.svm.core.hub.crema.CremaResolvedJavaType;
4040
import com.oracle.svm.core.hub.crema.CremaSupport;
4141
import com.oracle.svm.core.reflect.target.ReflectionObjectFactory;
42+
import com.oracle.svm.shared.util.VMError;
4243

4344
import jdk.vm.ci.meta.JavaType;
4445
import jdk.vm.ci.meta.ResolvedJavaType;
@@ -185,6 +186,12 @@ public RecordComponent[] getRecordComponents(DynamicHub declaringClass, @Suppres
185186
return result;
186187
}
187188

189+
@Override
190+
public RuntimeDynamicAccessMetadata getUnsafeAllocationMetadata(DynamicHub dynamicHub, int layerNum) {
191+
/* Unsafe allocation is always allowed for runtime created classes */
192+
throw VMError.intentionallyUnimplemented();
193+
}
194+
188195
private static Class<?> toClassOrThrow(JavaType javaType, ResolvedJavaType accessingType) {
189196
if (javaType instanceof UnresolvedJavaType unresolvedJavaType) {
190197
return CremaSupport.singleton().resolveOrThrow(unresolvedJavaType, accessingType);

0 commit comments

Comments
 (0)