diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java index 1c717b14b356..25ee6b2eeef1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java @@ -45,6 +45,8 @@ import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RestrictHeapAccess.Access; import com.oracle.svm.core.heap.VMOperationInfos; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.option.HostedOptionKey; @@ -99,6 +101,17 @@ public static CodeInfo getFirstImageCodeInfo() { return imageCodeInfo; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static CodeInfo getFirstImageCodeInfo(int layerNumber) { + if (ImageLayerBuildingSupport.buildingImageLayer()) { + ImageCodeInfoStorage[] runtimeCodeInfos = MultiLayeredImageSingleton.getAllLayers(ImageCodeInfoStorage.class); + return runtimeCodeInfos[layerNumber].getData(); + } else { + assert layerNumber == 0; + return imageCodeInfo; + } + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static CodeInfo getImageCodeInfo(CodePointer ip) { CodeInfo info = lookupImageCodeInfo(ip); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java index 6cf24e39bfcc..192c05b3d396 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java @@ -32,7 +32,9 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.lang.reflect.RecordComponent; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.function.Function; import org.graalvm.nativeimage.ImageSingletons; @@ -44,6 +46,7 @@ import com.oracle.svm.core.configure.RuntimeConditionSet; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; import com.oracle.svm.core.reflect.RuntimeMetadataDecoder; import com.oracle.svm.core.reflect.target.ReflectionObjectFactory; import com.oracle.svm.core.reflect.target.Target_java_lang_reflect_Executable; @@ -92,8 +95,12 @@ public class RuntimeMetadataDecoderImpl implements RuntimeMetadataDecoder { // Value from Reflection.getClassAccessFlags() public static final int CLASS_ACCESS_FLAGS_MASK = 0x1FFF; - static byte[] getEncoding() { - return ImageSingletons.lookup(RuntimeMetadataEncoding.class).getEncoding(); + static byte[] getEncoding(DynamicHub hub) { + return MultiLayeredImageSingleton.getAllLayers(RuntimeMetadataEncoding.class)[hub.getLayerId()].getEncoding(); + } + + static List getEncodings() { + return Arrays.stream(MultiLayeredImageSingleton.getAllLayers(RuntimeMetadataEncoding.class)).map(RuntimeMetadataEncoding::getEncoding).toList(); } /** @@ -105,14 +112,16 @@ static byte[] getEncoding() { */ @Override public Field[] parseFields(DynamicHub declaringType, int index, boolean publicOnly) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, Field.class, (i) -> (Field) decodeField(reader, DynamicHub.toClass(declaringType), publicOnly, true)); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, Field.class, (i) -> (Field) decodeField(reader, DynamicHub.toClass(declaringType), publicOnly, true, layerId), layerId); } @Override public FieldDescriptor[] parseReachableFields(DynamicHub declaringType, int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, FieldDescriptor.class, (i) -> (FieldDescriptor) decodeField(reader, DynamicHub.toClass(declaringType), false, false)); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, FieldDescriptor.class, (i) -> (FieldDescriptor) decodeField(reader, DynamicHub.toClass(declaringType), false, false, layerId), layerId); } /** @@ -124,14 +133,16 @@ public FieldDescriptor[] parseReachableFields(DynamicHub declaringType, int inde */ @Override public Method[] parseMethods(DynamicHub declaringType, int index, boolean publicOnly) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, Method.class, (i) -> (Method) decodeExecutable(reader, DynamicHub.toClass(declaringType), publicOnly, true, true)); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, Method.class, (i) -> (Method) decodeExecutable(reader, DynamicHub.toClass(declaringType), publicOnly, true, true, layerId), layerId); } @Override public MethodDescriptor[] parseReachableMethods(DynamicHub declaringType, int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, MethodDescriptor.class, (i) -> (MethodDescriptor) decodeExecutable(reader, DynamicHub.toClass(declaringType), false, false, true)); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, MethodDescriptor.class, (i) -> (MethodDescriptor) decodeExecutable(reader, DynamicHub.toClass(declaringType), false, false, true, layerId), layerId); } /** @@ -143,14 +154,17 @@ public MethodDescriptor[] parseReachableMethods(DynamicHub declaringType, int in */ @Override public Constructor[] parseConstructors(DynamicHub declaringType, int index, boolean publicOnly) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, Constructor.class, (i) -> (Constructor) decodeExecutable(reader, DynamicHub.toClass(declaringType), publicOnly, true, false)); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, Constructor.class, (i) -> (Constructor) decodeExecutable(reader, DynamicHub.toClass(declaringType), publicOnly, true, false, layerId), layerId); } @Override public ConstructorDescriptor[] parseReachableConstructors(DynamicHub declaringType, int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, ConstructorDescriptor.class, (i) -> (ConstructorDescriptor) decodeExecutable(reader, DynamicHub.toClass(declaringType), false, false, false)); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, ConstructorDescriptor.class, (i) -> (ConstructorDescriptor) decodeExecutable(reader, DynamicHub.toClass(declaringType), false, false, false, layerId), + layerId); } /** @@ -161,9 +175,23 @@ public ConstructorDescriptor[] parseReachableConstructors(DynamicHub declaringTy * */ @Override - public Class[] parseClasses(int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, Class.class, (i) -> decodeType(reader)); + public Class[] parseClasses(int index, DynamicHub declaringType) { + return parseClasses(index, getEncoding(declaringType), declaringType.getLayerId()); + } + + @Override + public Class[] parseAllClasses() { + List encodings = getEncodings(); + List> reachableClassesList = new ArrayList<>(); + for (int i = 0; i < encodings.size(); ++i) { + reachableClassesList.addAll(Arrays.stream(parseClasses(0, encodings.get(i), i)).toList()); + } + return reachableClassesList.toArray(new Class[0]); + } + + private static Class[] parseClasses(int index, byte[] encoding, int layerId) { + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(encoding, index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, Class.class, (i) -> decodeType(reader, layerId), layerId); } /** @@ -175,8 +203,9 @@ public Class[] parseClasses(int index) { */ @Override public RecordComponent[] parseRecordComponents(DynamicHub declaringType, int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, RecordComponent.class, (i) -> decodeRecordComponent(reader, DynamicHub.toClass(declaringType))); + int layerId = declaringType.getLayerId(); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + return decodeArray(reader, RecordComponent.class, (i) -> decodeRecordComponent(reader, DynamicHub.toClass(declaringType), layerId), layerId); } /** @@ -187,9 +216,10 @@ public RecordComponent[] parseRecordComponents(DynamicHub declaringType, int ind * */ @Override - public Object[] parseObjects(int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, Object.class, (i) -> decodeObject(reader)); + public Object[] parseObjects(int index, DynamicHub declaringType) { + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + int layerId = declaringType.getLayerId(); + return decodeArray(reader, Object.class, (i) -> decodeObject(reader, layerId), layerId); } /** @@ -201,9 +231,10 @@ public Object[] parseObjects(int index) { * */ @Override - public Parameter[] parseReflectParameters(Executable executable, byte[] encoding) { + public Parameter[] parseReflectParameters(Executable executable, byte[] encoding, DynamicHub declaringType) { + int layerId = declaringType.getLayerId(); UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(encoding, 0, ByteArrayReader.supportsUnalignedMemoryAccess()); - return decodeArray(reader, Parameter.class, (i) -> decodeReflectParameter(reader, executable, i)); + return decodeArray(reader, Parameter.class, (i) -> decodeReflectParameter(reader, executable, i, layerId), layerId); } /** @@ -218,20 +249,21 @@ public Parameter[] parseReflectParameters(Executable executable, byte[] encoding * */ @Override - public Object[] parseEnclosingMethod(int index) { + public Object[] parseEnclosingMethod(int index, DynamicHub declaringType) { + int layerId = declaringType.getLayerId(); if (isErrorIndex(index)) { - decodeAndThrowError(index); + decodeAndThrowError(index, layerId); } - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); - Class declaringClass = decodeType(reader); - String name = decodeMemberName(reader); - String descriptor = decodeOtherString(reader); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + Class declaringClass = decodeType(reader, layerId); + String name = decodeMemberName(reader, layerId); + String descriptor = decodeOtherString(reader, layerId); return new Object[]{declaringClass, name, descriptor}; } @Override - public byte[] parseByteArray(int index) { - UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(), index, ByteArrayReader.supportsUnalignedMemoryAccess()); + public byte[] parseByteArray(int index, DynamicHub declaringType) { + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(getEncoding(declaringType), index, ByteArrayReader.supportsUnalignedMemoryAccess()); return decodeByteArray(reader); } @@ -258,10 +290,10 @@ public static boolean isErrorIndex(int index) { * Errors are encoded as negated indices of the frame info object constants array. */ @SuppressWarnings("unchecked") - private static void decodeAndThrowError(int index) throws T { + private static void decodeAndThrowError(int index, int layerId) throws T { assert isErrorIndex(index); int decodedIndex = FIRST_ERROR_INDEX - index; - throw (T) MetadataAccessor.singleton().getObject(decodedIndex); + throw (T) MetadataAccessor.singleton().getObject(decodedIndex, layerId); } /** @@ -318,14 +350,14 @@ private static void decodeAndThrowError(int index) throws * } * */ - private static Object decodeField(UnsafeArrayTypeReader buf, Class declaringClass, boolean publicOnly, boolean reflectOnly) { + private static Object decodeField(UnsafeArrayTypeReader buf, Class declaringClass, boolean publicOnly, boolean reflectOnly, int layerId) { int modifiers = buf.getUVInt(); boolean inHeap = (modifiers & IN_HEAP_FLAG_MASK) != 0; boolean complete = (modifiers & COMPLETE_FLAG_MASK) != 0; - RuntimeConditionSet conditions = decodeConditions(buf); + RuntimeConditionSet conditions = decodeConditions(buf, layerId); if (inHeap) { - Field field = (Field) decodeObject(buf); + Field field = (Field) decodeObject(buf, layerId); if (publicOnly && !Modifier.isPublic(field.getModifiers())) { /* * Generate negative copy of the field. Finding a non-public field when looking for @@ -346,8 +378,8 @@ private static Object decodeField(UnsafeArrayTypeReader buf, Class declaringC assert !(negative && (complete || hiding)); modifiers &= ~COMPLETE_FLAG_MASK; - String name = decodeMemberName(buf); - Class type = (complete || hiding) ? decodeType(buf) : null; + String name = decodeMemberName(buf, layerId); + Class type = (complete || hiding) ? decodeType(buf, layerId) : null; if (!complete) { if (reflectOnly != (hiding || negative)) { /* @@ -364,11 +396,11 @@ private static Object decodeField(UnsafeArrayTypeReader buf, Class declaringC null); } boolean trustedFinal = buf.getU1() == 1; - String signature = decodeOtherString(buf); + String signature = decodeOtherString(buf, layerId); byte[] annotations = decodeByteArray(buf); byte[] typeAnnotations = decodeByteArray(buf); int offset = buf.getSVInt(); - String deletedReason = decodeOtherString(buf); + String deletedReason = decodeOtherString(buf, layerId); if (publicOnly && !Modifier.isPublic(modifiers)) { modifiers |= NEGATIVE_FLAG_MASK; } @@ -377,8 +409,8 @@ private static Object decodeField(UnsafeArrayTypeReader buf, Class declaringC return reflectOnly ? reflectField : new FieldDescriptor(reflectField); } - private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf) { - var conditionTypes = decodeArray(buf, Class.class, i -> decodeType(buf)); + private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf, int layerId) { + var conditionTypes = decodeArray(buf, Class.class, i -> decodeType(buf, layerId), layerId); return RuntimeConditionSet.createDecoded(conditionTypes); } @@ -397,7 +429,7 @@ private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf) { * byte[] parameterAnnotationsEncoding * byte[] annotationDefaultEncoding (annotation methods only) * byte[] typeAnnotationsEncoding - * byte[] reflectParametersEncoding ({@link #decodeReflectParameter(UnsafeArrayTypeReader, Executable, int)}) + * byte[] reflectParametersEncoding ({@link #decodeReflectParameter(UnsafeArrayTypeReader, Executable, int, int)}) * ObjectIndex accessor (null if registered as queried only) * } * @@ -453,7 +485,7 @@ private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf) { * byte[] annotationsEncoding * byte[] parameterAnnotationsEncoding * byte[] typeAnnotationsEncoding - * byte[] reflectParametersEncoding ({@link #parseReflectParameters(Executable, byte[])}) + * byte[] reflectParametersEncoding ({@link RuntimeMetadataDecoder#parseReflectParameters(Executable, byte[], DynamicHub)}) * ObjectIndex accessor (null if registered as queried only) * } * @@ -485,13 +517,13 @@ private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf) { * } * */ - private static Object decodeExecutable(UnsafeArrayTypeReader buf, Class declaringClass, boolean publicOnly, boolean reflectOnly, boolean isMethod) { + private static Object decodeExecutable(UnsafeArrayTypeReader buf, Class declaringClass, boolean publicOnly, boolean reflectOnly, boolean isMethod, int layerId) { int modifiers = buf.getUVInt(); boolean inHeap = (modifiers & IN_HEAP_FLAG_MASK) != 0; boolean complete = (modifiers & COMPLETE_FLAG_MASK) != 0; - RuntimeConditionSet conditions = decodeConditions(buf); + RuntimeConditionSet conditions = decodeConditions(buf, layerId); if (inHeap) { - Executable executable = (Executable) decodeObject(buf); + Executable executable = (Executable) decodeObject(buf, layerId); if (publicOnly && !Modifier.isPublic(executable.getModifiers())) { /* * Generate negative copy of the executable. Finding a non-public method when @@ -523,14 +555,14 @@ private static Object decodeExecutable(UnsafeArrayTypeReader buf, Class decla assert !(negative && (complete || hiding)); modifiers &= ~COMPLETE_FLAG_MASK; - String name = isMethod ? decodeMemberName(buf) : null; + String name = isMethod ? decodeMemberName(buf, layerId) : null; Object[] parameterTypes; if (complete || hiding || negative) { - parameterTypes = decodeArray(buf, Class.class, (i) -> decodeType(buf)); + parameterTypes = decodeArray(buf, Class.class, (i) -> decodeType(buf, layerId), layerId); } else { - parameterTypes = decodeArray(buf, String.class, (i) -> decodeOtherString(buf)); + parameterTypes = decodeArray(buf, String.class, (i) -> decodeOtherString(buf, layerId), layerId); } - Class returnType = isMethod && (complete || hiding) ? decodeType(buf) : null; + Class returnType = isMethod && (complete || hiding) ? decodeType(buf, layerId) : null; if (!complete) { if (reflectOnly != (hiding || negative)) { /* @@ -553,14 +585,14 @@ private static Object decodeExecutable(UnsafeArrayTypeReader buf, Class decla return ReflectionObjectFactory.newConstructor(conditions, declaringClass, (Class[]) parameterTypes, null, modifiers, null, null, null, null, null, null); } } - Class[] exceptionTypes = decodeArray(buf, Class.class, (i) -> decodeType(buf)); - String signature = decodeOtherString(buf); + Class[] exceptionTypes = decodeArray(buf, Class.class, (i) -> decodeType(buf, layerId), layerId); + String signature = decodeOtherString(buf, layerId); byte[] annotations = decodeByteArray(buf); byte[] parameterAnnotations = decodeByteArray(buf); byte[] annotationDefault = isMethod && declaringClass.isAnnotation() ? decodeByteArray(buf) : null; byte[] typeAnnotations = decodeByteArray(buf); byte[] reflectParameters = decodeByteArray(buf); - Object accessor = decodeObject(buf); + Object accessor = decodeObject(buf, layerId); if (publicOnly && !Modifier.isPublic(modifiers)) { modifiers |= NEGATIVE_FLAG_MASK; } @@ -597,10 +629,10 @@ private static Object decodeExecutable(UnsafeArrayTypeReader buf, Class decla * } * */ - private static RecordComponent decodeRecordComponent(UnsafeArrayTypeReader buf, Class declaringClass) { - String name = decodeMemberName(buf); - Class type = decodeType(buf); - String signature = decodeOtherString(buf); + private static RecordComponent decodeRecordComponent(UnsafeArrayTypeReader buf, Class declaringClass, int layerId) { + String name = decodeMemberName(buf, layerId); + Class type = decodeType(buf, layerId); + String signature = decodeOtherString(buf, layerId); byte[] annotations = decodeByteArray(buf); byte[] typeAnnotations = decodeByteArray(buf); @@ -618,34 +650,34 @@ private static RecordComponent decodeRecordComponent(UnsafeArrayTypeReader buf, * */ - private static Parameter decodeReflectParameter(UnsafeArrayTypeReader buf, Executable executable, int i) { - String name = decodeOtherString(buf); + private static Parameter decodeReflectParameter(UnsafeArrayTypeReader buf, Executable executable, int i, int layerId) { + String name = decodeOtherString(buf, layerId); int modifiers = buf.getUVInt(); return ReflectionObjectFactory.newParameter(executable, i, name, modifiers); } /** Types are encoded as indices in the code info classes array. */ - private static Class decodeType(UnsafeArrayTypeReader buf) { + private static Class decodeType(UnsafeArrayTypeReader buf, int layerId) { int classIndex = buf.getSVInt(); if (classIndex == NO_METHOD_METADATA) { return null; } - return MetadataAccessor.singleton().getClass(classIndex); + return MetadataAccessor.singleton().getClass(classIndex, layerId); } /** Names are encoded as indices in the code info member names array. */ - private static String decodeMemberName(UnsafeArrayTypeReader buf) { + private static String decodeMemberName(UnsafeArrayTypeReader buf, int layerId) { int nameIndex = buf.getSVInt(); - String name = MetadataAccessor.singleton().getMemberName(nameIndex); + String name = MetadataAccessor.singleton().getMemberName(nameIndex, layerId); /* Interning the string to ensure JDK8 method search succeeds */ return name == null ? null : name.intern(); } /** Strings other than member names are encoded as indices in the code info strings array. */ - private static String decodeOtherString(UnsafeArrayTypeReader buf) { + private static String decodeOtherString(UnsafeArrayTypeReader buf, int layerId) { int nameIndex = buf.getSVInt(); - String name = MetadataAccessor.singleton().getOtherString(nameIndex); + String name = MetadataAccessor.singleton().getOtherString(nameIndex, layerId); /* Interning the string to ensure JDK8 method search succeeds */ return name == null ? null : name.intern(); } @@ -654,22 +686,22 @@ private static String decodeOtherString(UnsafeArrayTypeReader buf) { * Objects (method accessors and reflection objects in the heap) are encoded as indices in the * code info object constants array. */ - private static Object decodeObject(UnsafeArrayTypeReader buf) { + private static Object decodeObject(UnsafeArrayTypeReader buf, int layerId) { int objectIndex = buf.getSVInt(); if (objectIndex == NULL_OBJECT) { return null; } - return MetadataAccessor.singleton().getObject(objectIndex); + return MetadataAccessor.singleton().getObject(objectIndex, layerId); } /** * Arrays are encoded by their length followed by the elements encoded one after the other. */ @SuppressWarnings("unchecked") - private static T[] decodeArray(UnsafeArrayTypeReader buf, Class elementType, Function elementDecoder) { + private static T[] decodeArray(UnsafeArrayTypeReader buf, Class elementType, Function elementDecoder, int layerId) { int length = buf.getSVInt(); if (isErrorIndex(length)) { - decodeAndThrowError(length); + decodeAndThrowError(length, layerId); } T[] result = (T[]) Array.newInstance(elementType, length); int valueCount = 0; @@ -703,32 +735,32 @@ public static class MetadataAccessorImpl implements MetadataAccessor { @Override @SuppressWarnings("unchecked") - public T getObject(int index) { - CodeInfo info = getCodeInfo(); + public T getObject(int index, int layerId) { + CodeInfo info = getCodeInfo(layerId); return (T) NonmovableArrays.getObject(CodeInfoAccess.getObjectConstants(info), index); } @Override - public Class getClass(int index) { - CodeInfo info = getCodeInfo(); + public Class getClass(int index, int layerId) { + CodeInfo info = getCodeInfo(layerId); return NonmovableArrays.getObject(CodeInfoAccess.getClasses(info), index); } @Override - public String getMemberName(int index) { - CodeInfo info = getCodeInfo(); + public String getMemberName(int index, int layerId) { + CodeInfo info = getCodeInfo(layerId); return NonmovableArrays.getObject(CodeInfoAccess.getMemberNames(info), index); } @Override - public String getOtherString(int index) { - CodeInfo info = getCodeInfo(); + public String getOtherString(int index, int layerId) { + CodeInfo info = getCodeInfo(layerId); return NonmovableArrays.getObject(CodeInfoAccess.getOtherStrings(info), index); } /** @see com.oracle.svm.core.code.RuntimeMetadataEncoding */ - private static CodeInfo getCodeInfo() { - return CodeInfoTable.getFirstImageCodeInfo(); + private static CodeInfo getCodeInfo(int layerId) { + return CodeInfoTable.getFirstImageCodeInfo(layerId); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataEncoding.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataEncoding.java index c5b5d372243d..7ac7c635b684 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataEncoding.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataEncoding.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.code; +import java.util.EnumSet; + import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -31,6 +33,9 @@ import com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.MetadataAccessorImpl; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton; /** * Stores the encoding of all runtime metadata. @@ -43,7 +48,7 @@ * we would need an index to locate all relevant runtime metadata of an entity from all layers. */ @AutomaticallyRegisteredImageSingleton -public class RuntimeMetadataEncoding { +public class RuntimeMetadataEncoding implements MultiLayeredImageSingleton, UnsavedSingleton { @UnknownObjectField(availability = AfterCompilation.class) private byte[] encoding; public byte[] getEncoding() { @@ -54,4 +59,9 @@ public byte[] getEncoding() { public void setEncoding(byte[] encoding) { this.encoding = encoding; } + + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.ALL_ACCESS; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java index 84ca0c021e61..5cb9f6a51e25 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java @@ -26,6 +26,7 @@ import static com.oracle.svm.core.MissingRegistrationUtils.throwMissingRegistrationErrors; +import java.util.EnumSet; import java.util.Objects; import org.graalvm.collections.EconomicMap; @@ -37,12 +38,15 @@ import com.oracle.svm.core.configure.ConditionalRuntimeValue; import com.oracle.svm.core.configure.RuntimeConditionSet; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton; import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils; import com.oracle.svm.core.util.ImageHeapMap; import com.oracle.svm.core.util.VMError; @AutomaticallyRegisteredImageSingleton -public final class ClassForNameSupport { +public final class ClassForNameSupport implements MultiLayeredImageSingleton, UnsavedSingleton { public static ClassForNameSupport singleton() { return ImageSingletons.lookup(ClassForNameSupport.class); @@ -159,7 +163,7 @@ private void updateCondition(ConfigurationCondition condition, String className, } } - public Class forNameOrNull(String className, ClassLoader classLoader) { + public static Class forNameOrNull(String className, ClassLoader classLoader) { try { return forName(className, classLoader, true); } catch (ClassNotFoundException e) { @@ -167,23 +171,17 @@ public Class forNameOrNull(String className, ClassLoader classLoader) { } } - public Class forName(String className, ClassLoader classLoader) throws ClassNotFoundException { + public static Class forName(String className, ClassLoader classLoader) throws ClassNotFoundException { return forName(className, classLoader, false); } - private Class forName(String className, ClassLoader classLoader, boolean returnNullOnException) throws ClassNotFoundException { + private static Class forName(String className, ClassLoader classLoader, boolean returnNullOnException) throws ClassNotFoundException { if (className == null) { return null; } - var conditional = knownClasses.get(className); - Object result = conditional == null ? null : conditional.getValue(); - if (result == NEGATIVE_QUERY || className.endsWith("[]")) { - /* Querying array classes with their "TypeName[]" name always throws */ - result = new ClassNotFoundException(className); - } - if (result == null) { - result = PredefinedClassesSupport.getLoadedForNameOrNull(className, classLoader); - } + ClassForNameSupport classForNameSupport = singleton(); + Object result = classForNameSupport.getSingletonData(classForNameSupport, MultiLayeredImageSingleton.getAllLayers(ClassForNameSupport.class), + singleton -> singleton.forName0(className, classLoader)); // Note: for non-predefined classes, we (currently) don't need to check the provided loader // TODO rewrite stack traces (GR-42813) if (result instanceof Class) { @@ -212,13 +210,29 @@ private Class forName(String className, ClassLoader classLoader, boolean retu throw VMError.shouldNotReachHere("Class.forName result should be Class, ClassNotFoundException or Error: " + result); } + private Object forName0(String className, ClassLoader classLoader) { + var conditional = knownClasses.get(className); + Object result = conditional == null ? null : conditional.getValue(); + if (result == NEGATIVE_QUERY || className.endsWith("[]")) { + /* Querying array classes with their "TypeName[]" name always throws */ + result = new ClassNotFoundException(className); + } + if (result == null) { + result = PredefinedClassesSupport.getLoadedForNameOrNull(className, classLoader); + } + return result; + } + public int count() { return knownClasses.size(); } - public RuntimeConditionSet getConditionFor(Class jClass) { + public static RuntimeConditionSet getConditionFor(Class jClass) { Objects.requireNonNull(jClass); - ConditionalRuntimeValue conditionalClass = knownClasses.get(jClass.getName()); + String jClassName = jClass.getName(); + ClassForNameSupport classForNameSupport = singleton(); + ConditionalRuntimeValue conditionalClass = classForNameSupport.getSingletonData(classForNameSupport, MultiLayeredImageSingleton.getAllLayers(ClassForNameSupport.class), + singleton -> singleton.knownClasses.get(jClassName)); if (conditionalClass == null) { return RuntimeConditionSet.unmodifiableEmptySet(); } else { @@ -230,8 +244,16 @@ public RuntimeConditionSet getConditionFor(Class jClass) { * 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)); + public static boolean canUnsafeInstantiateAsInstance(DynamicHub hub) { + Class clazz = DynamicHub.toClass(hub); + ClassForNameSupport classForNameSupport = singleton(); + RuntimeConditionSet conditionSet = classForNameSupport.getSingletonData(classForNameSupport, MultiLayeredImageSingleton.getAllLayers(ClassForNameSupport.class), + singleton -> singleton.unsafeInstantiatedClasses.get(clazz)); return conditionSet != null && conditionSet.satisfied(); } + + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.ALL_ACCESS; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 7c88c23dbace..a2c6fc6fb67e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -762,7 +762,7 @@ public boolean canUnsafeInstantiateAsInstanceFastPath() { } public boolean canUnsafeInstantiateAsInstanceSlowPath() { - if (ClassForNameSupport.singleton().canUnsafeInstantiateAsInstance(this)) { + if (ClassForNameSupport.canUnsafeInstantiateAsInstance(this)) { companion.setUnsafeAllocate(); return true; } else { @@ -1110,7 +1110,7 @@ private Field[] getFields() { } private RuntimeConditionSet getConditions() { - return ClassForNameSupport.singleton().getConditionFor(DynamicHub.toClass(this)); + return ClassForNameSupport.getConditionFor(DynamicHub.toClass(this)); } @Substitute @@ -1498,7 +1498,7 @@ private static Class forName(String name, boolean initialize, ClassLoader loa } Class result; try { - result = ClassForNameSupport.singleton().forName(name, loader); + result = ClassForNameSupport.forName(name, loader); } catch (ClassNotFoundException e) { if (loader != null && PredefinedClassesSupport.hasBytecodeClasses()) { result = loader.loadClass(name); // may throw @@ -1577,7 +1577,7 @@ public Object[] getSigners() { if (hubMetadata == null || hubMetadata.signersEncodingIndex == NO_DATA) { return null; } - return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseObjects(hubMetadata.signersEncodingIndex); + return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseObjects(hubMetadata.signersEncodingIndex, this); } @Substitute @@ -1725,7 +1725,7 @@ private Object[] getEnclosingMethod0() { if (hubMetadata == null || hubMetadata.enclosingMethodInfoIndex == NO_DATA) { return null; } - Object[] enclosingMethod = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseEnclosingMethod(hubMetadata.enclosingMethodInfoIndex); + Object[] enclosingMethod = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseEnclosingMethod(hubMetadata.enclosingMethodInfoIndex, this); if (enclosingMethod != null) { PredefinedClassesSupport.throwIfUnresolvable((Class) enclosingMethod[0], getClassLoader0()); } @@ -1761,7 +1761,7 @@ byte[] getRawAnnotations() { if (hubMetadata == null || hubMetadata.annotationsIndex == NO_DATA) { return null; } - return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseByteArray(hubMetadata.annotationsIndex); + return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseByteArray(hubMetadata.annotationsIndex, this); } @Substitute @@ -1769,7 +1769,7 @@ byte[] getRawTypeAnnotations() { if (hubMetadata == null || hubMetadata.typeAnnotationsIndex == NO_DATA) { return null; } - return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseByteArray(hubMetadata.typeAnnotationsIndex); + return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseByteArray(hubMetadata.typeAnnotationsIndex, this); } @Substitute @@ -1806,7 +1806,7 @@ private Class[] getDeclaredClasses0() { if (hubMetadata == null || hubMetadata.classesEncodingIndex == NO_DATA) { return new Class[0]; } - Class[] declaredClasses = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseClasses(hubMetadata.classesEncodingIndex); + Class[] declaredClasses = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseClasses(hubMetadata.classesEncodingIndex, this); for (Class clazz : declaredClasses) { PredefinedClassesSupport.throwIfUnresolvable(clazz, getClassLoader0()); } @@ -1825,7 +1825,7 @@ private Class[] getNestMembers0() { if (hubMetadata == null || hubMetadata.nestMembersEncodingIndex == NO_DATA) { return new Class[]{DynamicHub.toClass(this)}; } - Class[] nestMembers = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseClasses(hubMetadata.nestMembersEncodingIndex); + Class[] nestMembers = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseClasses(hubMetadata.nestMembersEncodingIndex, this); for (Class clazz : nestMembers) { PredefinedClassesSupport.throwIfUnresolvable(clazz, getClassLoader0()); } @@ -1877,7 +1877,7 @@ private Class[] getPermittedSubclasses0() { if (hubMetadata == null || hubMetadata.permittedSubclassesEncodingIndex == NO_DATA) { return new Class[0]; } - Class[] permittedSubclasses = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseClasses(hubMetadata.permittedSubclassesEncodingIndex); + Class[] permittedSubclasses = ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseClasses(hubMetadata.permittedSubclassesEncodingIndex, this); for (Class clazz : permittedSubclasses) { PredefinedClassesSupport.throwIfUnresolvable(clazz, getClassLoader0()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 511e8fb2f5b1..cebc7225d4cd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -649,14 +649,14 @@ public static Stream packages() { @Substitute private static Class loadClassOrNull(String name) { - return ClassForNameSupport.singleton().forNameOrNull(name, null); + return ClassForNameSupport.forNameOrNull(name, null); } @SuppressWarnings("unused") @Substitute private static Class loadClass(Module module, String name) { /* The module system is not supported for now, therefore the module parameter is ignored. */ - return ClassForNameSupport.singleton().forNameOrNull(name, null); + return ClassForNameSupport.forNameOrNull(name, null); } @SuppressWarnings("unused") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java index a8f9d949113d..c3921c28c6e6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java @@ -165,7 +165,7 @@ Class loadClass(Module module, String name) { @Substitute // @SuppressWarnings({"unused"}) // private Class findLoadedClass0(String name) { - return ClassForNameSupport.singleton().forNameOrNull(name, SubstrateUtil.cast(this, ClassLoader.class)); + return ClassForNameSupport.forNameOrNull(name, SubstrateUtil.cast(this, ClassLoader.class)); } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java index 0bf7aeae10ac..b6f0b8bfe6d1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java @@ -24,6 +24,9 @@ */ package com.oracle.svm.core.layeredimagesingleton; +import java.util.function.Function; + +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.util.VMError; public interface MultiLayeredImageSingleton extends LayeredImageSingleton { @@ -36,4 +39,18 @@ public interface MultiLayeredImageSingleton extends LayeredImageSingleton { static T[] getAllLayers(Class key) { throw VMError.shouldNotReachHere("This can only be called during runtime"); } + + default U getSingletonData(T singleton, T[] singletons, Function getSingletonDataFunction) { + if (ImageLayerBuildingSupport.buildingImageLayer()) { + for (var layerSingleton : singletons) { + U result = getSingletonDataFunction.apply(layerSingleton); + if (result != null) { + return result; + } + } + return null; + } else { + return getSingletonDataFunction.apply(singleton); + } + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeMetadataDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeMetadataDecoder.java index 7f5bc97abd2e..843bc490b14b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeMetadataDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeMetadataDecoder.java @@ -52,17 +52,19 @@ public interface RuntimeMetadataDecoder { ConstructorDescriptor[] parseReachableConstructors(DynamicHub declaringType, int index); - Class[] parseClasses(int index); + Class[] parseClasses(int index, DynamicHub declaringType); + + Class[] parseAllClasses(); RecordComponent[] parseRecordComponents(DynamicHub declaringType, int index); - Object[] parseObjects(int index); + Object[] parseObjects(int index, DynamicHub declaringType); - Parameter[] parseReflectParameters(Executable executable, byte[] encoding); + Parameter[] parseReflectParameters(Executable executable, byte[] encoding, DynamicHub declaringType); - Object[] parseEnclosingMethod(int index); + Object[] parseEnclosingMethod(int index, DynamicHub declaringType); - byte[] parseByteArray(int index); + byte[] parseByteArray(int index, DynamicHub declaringType); boolean isHiding(int modifiers); @@ -153,12 +155,28 @@ static MetadataAccessor singleton() { return ImageSingletons.lookup(MetadataAccessor.class); } - T getObject(int index); + default T getObject(int index) { + return getObject(index, 0); + } + + default Class getClass(int index) { + return getClass(index, 0); + } + + default String getMemberName(int index) { + return getMemberName(index, 0); + } + + default String getOtherString(int index) { + return getOtherString(index, 0); + } + + T getObject(int index, int layerId); - Class getClass(int index); + Class getClass(int index, int layerId); - String getMemberName(int index); + String getMemberName(int index, int layerId); - String getOtherString(int index); + String getOtherString(int index, int layerId); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Executable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Executable.java index 12b5148acfd6..0b3bbfe3003c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Executable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Executable.java @@ -38,6 +38,7 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.reflect.RuntimeMetadataDecoder; @TargetClass(value = Executable.class) @@ -62,7 +63,9 @@ private Parameter[] getParameters0() { * We want the decoder to throw this exception. Our caller Executable.parameterData catches * it and converts it to a class format error. */ - return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseReflectParameters(SubstrateUtil.cast(this, Executable.class), rawParameters); + Executable executable = SubstrateUtil.cast(this, Executable.class); + DynamicHub declaringClass = DynamicHub.fromClass(executable.getDeclaringClass()); + return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseReflectParameters(executable, rawParameters, declaringClass); } @Substitute