Skip to content

Commit 459ce8b

Browse files
committed
Integrate unsafe allocation registration in ReflectionDataBuilder
1 parent 9e23cc2 commit 459ce8b

14 files changed

Lines changed: 163 additions & 114 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: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
import org.graalvm.nativeimage.ImageSingletons;
9292
import org.graalvm.nativeimage.Platform;
9393
import org.graalvm.nativeimage.Platforms;
94+
import org.graalvm.nativeimage.dynamicaccess.AccessCondition;
9495
import org.graalvm.nativeimage.impl.ClassLoadingSupport;
9596
import org.graalvm.nativeimage.impl.InternalPlatform.NATIVE_ONLY;
9697

@@ -143,6 +144,7 @@
143144
import com.oracle.svm.core.util.LazyFinalReference;
144145
import com.oracle.svm.guest.staging.Uninterruptible;
145146
import com.oracle.svm.shared.util.VMError;
147+
import com.oracle.svm.guest.staging.Uninterruptible;
146148
import com.oracle.svm.util.AnnotationUtil;
147149
import com.oracle.svm.util.GuestAccess;
148150
import com.oracle.svm.util.ReflectionUtil;
@@ -518,7 +520,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
518520
DynamicHubCompanion companion = DynamicHubCompanion.createAtRuntime(module, superHub, sourceFileName, modifiers, classLoader, simpleBinaryName, declaringClass, signature, info);
519521

520522
/* Always allow unsafe allocation for classes that were loaded at run-time. */
521-
companion.canUnsafeAllocate = true;
523+
companion.canUnsafeAllocate = RuntimeDynamicAccessMetadata.emptySet(false);
522524
companion.classInitializationInfo = ClassInitializationInfo.forRuntimeLoadedClass(false, hasClassInitializer);
523525
byte additionalFlags = NumUtil.safeToUByte((companion.additionalFlags & 0xff) | makeFlag(ADDITIONAL_FLAGS_INSTANTIATED_BIT, true));
524526
writeByte(companion, dynamicHubOffsets.getCompanionAdditionalFlagsOffset(), additionalFlags);
@@ -800,9 +802,10 @@ private DynamicHubMetadata hubMetadata() {
800802
}
801803

802804
@Platforms(Platform.HOSTED_ONLY.class)
803-
public void setReflectionMetadata(int fieldsEncodingIndex, int methodsEncodingIndex, int constructorsEncodingIndex, int recordComponentsEncodingIndex, int classFlags) {
805+
public void setReflectionMetadata(int fieldsEncodingIndex, int methodsEncodingIndex, int constructorsEncodingIndex, int recordComponentsEncodingIndex, int unsafeAllocationIndex, int classFlags) {
804806
assert companion.reflectionMetadata == null;
805-
ImageReflectionMetadata reflectionMetadata = new ImageReflectionMetadata(fieldsEncodingIndex, methodsEncodingIndex, constructorsEncodingIndex, recordComponentsEncodingIndex, classFlags);
807+
ImageReflectionMetadata reflectionMetadata = new ImageReflectionMetadata(fieldsEncodingIndex, methodsEncodingIndex, constructorsEncodingIndex, recordComponentsEncodingIndex,
808+
unsafeAllocationIndex, classFlags);
806809
if (ImageLayerBuildingSupport.buildingImageLayer()) {
807810
LayeredReflectionMetadataSingleton.currentLayer().setReflectionMetadata(this, reflectionMetadata);
808811
} else {
@@ -1058,24 +1061,29 @@ public boolean isInstantiated() {
10581061
}
10591062

10601063
public boolean canUnsafeInstantiateAsInstanceFastPath() {
1061-
return canUnsafeAllocate();
1064+
return companion.canUnsafeAllocate != null && companion.canUnsafeAllocate.fastPathSatisfied();
10621065
}
10631066

10641067
public boolean canUnsafeInstantiateAsInstanceSlowPath() {
1065-
if (ClassForNameSupport.canUnsafeInstantiateAsInstance(this)) {
1066-
setCanUnsafeAllocate();
1067-
return true;
1068-
} else {
1069-
return false;
1070-
}
1068+
RuntimeDynamicAccessMetadata canUnsafeAllocate = canUnsafeAllocate();
1069+
return canUnsafeAllocate != null && canUnsafeAllocate.satisfied();
10711070
}
10721071

1073-
public boolean canUnsafeAllocate() {
1072+
private RuntimeDynamicAccessMetadata canUnsafeAllocate() {
1073+
if (companion.canUnsafeAllocate == null) {
1074+
companion.canUnsafeAllocate = reflectionMetadata().getUnsafeAllocationMetadata(this, layerId);
1075+
}
10741076
return companion.canUnsafeAllocate;
10751077
}
10761078

1079+
@Platforms(Platform.HOSTED_ONLY.class)
10771080
public void setCanUnsafeAllocate() {
1078-
companion.canUnsafeAllocate = true;
1081+
companion.canUnsafeAllocate = RuntimeDynamicAccessMetadata.createHosted(AccessCondition.unconditional(), false);
1082+
}
1083+
1084+
public boolean isPreservedForUnsafeAllocation() {
1085+
RuntimeDynamicAccessMetadata canUnsafeAllocate = canUnsafeAllocate();
1086+
return canUnsafeAllocate != null && canUnsafeAllocate.isPreserved();
10791087
}
10801088

10811089
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.core.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);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeMetadataDecoder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import org.graalvm.nativeimage.ImageSingletons;
3737

38+
import com.oracle.svm.core.configure.RuntimeDynamicAccessMetadata;
3839
import com.oracle.svm.core.hub.DynamicHub;
3940
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
4041
import com.oracle.svm.core.reflect.target.Target_jdk_internal_reflect_ConstantPool;
@@ -70,6 +71,8 @@ public interface RuntimeMetadataDecoder {
7071

7172
byte[] parseByteArray(int index, DynamicHub declaringType);
7273

74+
RuntimeDynamicAccessMetadata parseDynamicAccessMetadata(int index, int layerId);
75+
7376
boolean isHiding(int modifiers);
7477

7578
boolean isNegative(int modifiers);

0 commit comments

Comments
 (0)