Skip to content

Commit 6b01a9f

Browse files
committed
Bugfixes
1 parent fa190bc commit 6b01a9f

File tree

11 files changed

+78
-122
lines changed

11 files changed

+78
-122
lines changed

docs/reference-manual/native-image/BuildOutput.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ To reduce overhead, please ensure that the classpath only contains entries that
9999
100100
#### <a name="glossary-reflection-registrations"></a>Reflection Registrations
101101
The number of classes, fields, and methods that are registered for reflection.
102-
Large numbers can cause significant reflection overheads, slow down the build process, and increase the size of the native image (see [method metadata](#glossary-method-metadata)).
102+
Large numbers can cause significant reflection overheads, slow down the build process, and increase the size of the native image (see [reflection metadata](#glossary-reflection-metadata)).
103103
104104
#### <a name="glossary-jni-access-registrations"></a>JNI Access Registrations
105105
The number of classes, fields, and methods that are registered for [JNI][doc_jni] access.
@@ -136,16 +136,16 @@ Therefore, reducing the number of [reachable methods](#glossary-reachability) al
136136
The image heap contains reachable objects such as static application data, metadata, and `byte[]` for different purposes.
137137
138138
##### <a name="glossary-general-heap-data"></a>General Heap Data Stored in `byte[]`
139-
The total size of all `byte[]` objects that are neither used for `java.lang.String`, nor [code metadata](#glossary-code-metadata), nor [method metadata](#glossary-method-metadata), nor [graph encodings](#glossary-graph-encodings).
139+
The total size of all `byte[]` objects that are neither used for `java.lang.String`, nor [code metadata](#glossary-code-metadata), nor [reflection metadata](#glossary-reflection-metadata), nor [graph encodings](#glossary-graph-encodings).
140140
Therefore, this can also include `byte[]` objects from application code.
141141
142142
##### <a name="glossary-code-metadata"></a>Code Metadata Stored in `byte[]`
143143
The total size of all `byte[]` objects used for metadata for the [code area](#glossary-code-area).
144144
Therefore, reducing the number of [reachable methods](#glossary-reachability) also reduces the size of this metadata.
145145
146-
##### <a name="glossary-method-metadata"></a>Method Metadata Stored in `byte[]`
147-
The total size of all `byte[]` objects used for method metadata, a type of reflection metadata.
148-
To reduce the amount of method metadata, reduce the number of [classes registered for reflection](#glossary-reflection-classes).
146+
##### <a name="glossary-reflection-metadata"></a>Reflection Metadata Stored in `byte[]`
147+
The total size of all `byte[]` objects used for reflection metadata, including class, field, method and constructor data.
148+
To reduce the amount of reflection metadata, reduce the number of [elements registered for reflection](#glossary-reflection-registrations).
149149
150150
##### <a name="glossary-graph-encodings"></a>Graph Encodings Stored in `byte[]`
151151
The total size of all `byte[]` objects used for graph encodings.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,11 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String ol
720720
}
721721
};
722722

723+
@SuppressWarnings("unused")//
724+
@APIOption(name = "configure-reflection-metadata")//
725+
@Option(help = "Enable runtime instantiation of reflection objects for non-invoked methods.", type = OptionType.Expert, deprecated = true)//
726+
public static final HostedOptionKey<Boolean> ConfigureReflectionMetadata = new HostedOptionKey<>(true);
727+
723728
@Option(help = "Include a list of methods included in the image for runtime inspection.", type = OptionType.Expert)//
724729
public static final HostedOptionKey<Boolean> IncludeMethodData = new HostedOptionKey<>(true);
725730

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,9 @@ private static ReflectionFactory getReflectionFactory() {
10341034
@KeepOriginal
10351035
private static native Field searchFields(Field[] fields, String name);
10361036

1037+
/**
1038+
* @see #filterHidingMethods(Method...)
1039+
*/
10371040
@Substitute
10381041
private static Method searchMethods(Method[] allMethods, String name, Class<?>[] parameterTypes) {
10391042
Method[] methods = filterHidingMethods(allMethods);
@@ -1057,6 +1060,9 @@ private static Method searchMethods(Method[] allMethods, String name, Class<?>[]
10571060
@KeepOriginal
10581061
private static native Field[] copyFields(Field[] arg);
10591062

1063+
/**
1064+
* @see #filterHidingMethods(Method...)
1065+
*/
10601066
@Substitute
10611067
private static Method[] copyMethods(Method[] original) {
10621068
Method[] arg = filterHidingMethods(original);
@@ -1235,6 +1241,9 @@ private String getSimpleBinaryName0() {
12351241
/* See open/src/hotspot/share/prims/jvm.cpp#1522. */
12361242
}
12371243

1244+
/**
1245+
* @see #filterHidingMethods(Method...)
1246+
*/
12381247
@Substitute //
12391248
@SuppressWarnings({"unused"})
12401249
List<Method> getDeclaredPublicMethods(String methodName, Class<?>... parameterTypes) {
@@ -1476,6 +1485,11 @@ private Class<?>[] getPermittedSubclasses0() {
14761485
@KeepOriginal
14771486
native AnnotationType getAnnotationType();
14781487

1488+
/*
1489+
* We need to filter out hiding methods at the last moment. This ensures that the JDK internals
1490+
* see them as regular methods and ensure the visibility of methods is correct, but they should
1491+
* not be returned to application code.
1492+
*/
14791493
private static Method[] filterHidingMethods(Method... methods) {
14801494
List<Method> filtered = new ArrayList<>();
14811495
for (Method method : methods) {
@@ -1510,6 +1524,13 @@ private static AnnotationType getAnnotationType(DynamicHub that) {
15101524
private static class CachedConstructorAccessors {
15111525
@SuppressWarnings("unused")
15121526
private static Constructor<?> getCachedConstructor(DynamicHub that) {
1527+
/*
1528+
* The JavaDoc for the Class.newInstance method states that "The class is initialized if
1529+
* it has not already been initialized". However, it doesn't specify if the absence of a
1530+
* nullary constructor will result in an InstantiationException before the class is
1531+
* initialized. We eagerly initialize the class to conform with JCK tests.
1532+
*/
1533+
that.ensureInitialized();
15131534
return that.companion.getCachedConstructor();
15141535
}
15151536

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ private Map<String, Long> calculateHeapBreakdown(Collection<ObjectInfo> heapObje
505505
}
506506
long metadataByteLength = ImageSingletons.lookup(ReflectionMetadataDecoder.class).getMetadataByteLength();
507507
if (metadataByteLength > 0) {
508-
classNameToSize.put(BREAKDOWN_BYTE_ARRAY_PREFIX + linkStrategy.asDocLink("reflection metadata", "#glossary-method-metadata"), metadataByteLength);
508+
classNameToSize.put(BREAKDOWN_BYTE_ARRAY_PREFIX + linkStrategy.asDocLink("reflection metadata", "#glossary-reflection-metadata"), metadataByteLength);
509509
remainingBytes -= metadataByteLength;
510510
}
511511
if (graphEncodingByteLength > 0) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package com.oracle.svm.hosted.heap;
2626

2727
import java.lang.reflect.AccessibleObject;
28+
import java.lang.reflect.Executable;
2829
import java.lang.reflect.Field;
2930
import java.util.function.Consumer;
3031

@@ -61,6 +62,7 @@ public class SVMImageHeapScanner extends ImageHeapScanner {
6162
private final Class<?> economicMapImpl;
6263
private final Field economicMapImplEntriesField;
6364
private final Field economicMapImplHashArrayField;
65+
private final RuntimeReflectionSupport reflectionSupport;
6466

6567
public SVMImageHeapScanner(ImageHeap imageHeap, ImageClassLoader loader, AnalysisMetaAccess metaAccess,
6668
SnippetReflectionProvider snippetReflection, ConstantReflectionProvider aConstantReflection, ObjectScanningObserver aScanningObserver) {
@@ -70,6 +72,7 @@ public SVMImageHeapScanner(ImageHeap imageHeap, ImageClassLoader loader, Analysi
7072
economicMapImplEntriesField = ReflectionUtil.lookupField(economicMapImpl, "entries");
7173
economicMapImplHashArrayField = ReflectionUtil.lookupField(economicMapImpl, "hashArray");
7274
ImageSingletons.add(ImageHeapScanner.class, this);
75+
reflectionSupport = ImageSingletons.lookup(RuntimeReflectionSupport.class);
7376
}
7477

7578
public static ImageHeapScanner instance() {
@@ -144,8 +147,8 @@ protected void onObjectReachable(ImageHeapObject imageHeapObject) {
144147
super.onObjectReachable(imageHeapObject);
145148

146149
Object object = SubstrateObjectConstant.asObject(imageHeapObject.getObject());
147-
if (object instanceof AccessibleObject) {
148-
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerHeapReflectionObject((AccessibleObject) object);
150+
if (object instanceof Field || object instanceof Executable) {
151+
reflectionSupport.registerHeapReflectionObject((AccessibleObject) object);
149152
}
150153
}
151154
}

substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ private static void registerTypesForReachableMethod(DuringAnalysisAccessImpl acc
463463
for (JavaType paramType : analysisMethod.toParameterTypes()) {
464464
makeAnalysisTypeReachable(access, (AnalysisType) paramType);
465465
}
466+
makeAnalysisTypeReachable(access, (AnalysisType) analysisMethod.getSignature().getReturnType(null));
466467
}
467468

468469
private void makeTypeReachable(DuringAnalysisAccessImpl access, Type type) {
@@ -524,11 +525,8 @@ private static void registerTypesForRecordComponent(DuringAnalysisAccessImpl acc
524525
}
525526
}
526527

527-
private static void registerTypesForAnnotation(DuringAnalysisAccessImpl accessImpl, Annotation annotation) {
528-
/*
529-
* Don't make annotation types reachable unless they have a chance of being queried.
530-
*/
531-
accessImpl.registerReachabilityHandler((access) -> registerTypesForAnnotationValue((DuringAnalysisAccessImpl) access, annotation.annotationType(), annotation), annotation.annotationType());
528+
private static void registerTypesForAnnotation(DuringAnalysisAccessImpl access, Annotation annotation) {
529+
registerTypesForAnnotationValue(access, annotation.annotationType(), annotation);
532530
}
533531

534532
@SuppressWarnings("unchecked")

substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionMetadataEncoderImpl.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import com.oracle.svm.core.annotate.Delete;
6363
import com.oracle.svm.core.code.CodeInfoEncoder;
6464
import com.oracle.svm.core.hub.DynamicHub;
65+
import com.oracle.svm.core.meta.DirectSubstrateObjectConstant;
6566
import com.oracle.svm.core.meta.SharedField;
6667
import com.oracle.svm.core.meta.SubstrateObjectConstant;
6768
import com.oracle.svm.core.reflect.ReflectionMetadataDecoder;
@@ -157,7 +158,22 @@ private void registerField(HostedType declaringType, FieldMetadata metadata) {
157158

158159
private void registerMethod(HostedType declaringType, MethodMetadata metadata) {
159160
sortedTypes.add(declaringType);
160-
methodData.computeIfAbsent(declaringType, t -> new HashSet<>()).add(metadata);
161+
methodData.computeIfAbsent(declaringType, t -> new TreeSet<>(ReflectionMetadataEncoderImpl::compareMethods)).add(metadata);
162+
}
163+
164+
/*
165+
* Force bridge methods at the end of the methods list so JCK tests see the real method first
166+
* when iterating through the list.
167+
*/
168+
private static int compareMethods(MethodMetadata left, MethodMetadata right) {
169+
boolean isLeftBridge = left.heapObject != null && ((Method) ((DirectSubstrateObjectConstant) left.heapObject).getObject()).isBridge();
170+
boolean isRightBridge = right.heapObject != null && ((Method) ((DirectSubstrateObjectConstant) right.heapObject).getObject()).isBridge();
171+
if (isLeftBridge != isRightBridge) {
172+
return isLeftBridge ? 1 : -1;
173+
} else {
174+
/* Ensure consistent ordering */
175+
return Integer.compare(left.hashCode(), right.hashCode());
176+
}
161177
}
162178

163179
private void registerConstructor(HostedType declaringType, ConstructorMetadata metadata) {
@@ -548,6 +564,7 @@ public void addReachableMethodMetadata(HostedMethod method) {
548564
HostedType declaringType = method.getDeclaringClass();
549565
String name = isMethod ? method.getName() : null;
550566
HostedType[] parameterTypes = getParameterTypes(method);
567+
HostedType returnType = (HostedType) method.getSignature().getReturnType(null);
551568
int modifiers = method.getModifiers();
552569

553570
/* Fill encoders with the necessary values. */
@@ -557,9 +574,10 @@ public void addReachableMethodMetadata(HostedMethod method) {
557574
for (HostedType parameterType : parameterTypes) {
558575
encoders.sourceClasses.addObject(parameterType.getJavaClass());
559576
}
577+
encoders.sourceClasses.addObject(returnType.getJavaClass());
560578

561579
if (isMethod) {
562-
registerMethod(declaringType, new MethodMetadata(false, declaringType, name, parameterTypes, modifiers, null));
580+
registerMethod(declaringType, new MethodMetadata(false, declaringType, name, parameterTypes, modifiers, returnType));
563581
} else {
564582
registerConstructor(declaringType, new ConstructorMetadata(declaringType, parameterTypes, modifiers));
565583
}
@@ -799,7 +817,7 @@ private void encodeExecutable(UnsafeArrayTypeWriter buf, ExecutableMetadata exec
799817
encodeName(buf, ((MethodMetadata) executable).name);
800818
}
801819
encodeArray(buf, executable.parameterTypes, parameterType -> encodeType(buf, parameterType));
802-
if (isMethod && (executable.complete || ((MethodMetadata) executable).hiding)) {
820+
if (isMethod) {
803821
encodeType(buf, ((MethodMetadata) executable).returnType);
804822
}
805823
if (executable.complete) {
@@ -1154,6 +1172,8 @@ private static void encodeTargetInfo(UnsafeArrayTypeWriter buf, TypeAnnotation.T
11541172
buf.putU1(THROWS);
11551173
buf.putU2(targetInfo.getCount());
11561174
break;
1175+
default:
1176+
throw GraalError.shouldNotReachHere("Unknown type annotation target: " + targetInfo.getTarget());
11571177
}
11581178
}
11591179

substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/proxy/DynamicProxySupport.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ public String toString() {
7878
}
7979
}
8080

81+
private final ClassLoader classLoader;
8182
private final Map<ProxyCacheKey, Object> proxyCache;
8283

83-
public DynamicProxySupport() {
84+
public DynamicProxySupport(ClassLoader classLoader) {
85+
this.classLoader = classLoader;
8486
this.proxyCache = new ConcurrentHashMap<>();
8587
}
8688

@@ -96,12 +98,16 @@ public void addProxyClass(Class<?>... interfaces) {
9698
proxyCache.computeIfAbsent(key, k -> {
9799
Class<?> clazz;
98100
try {
99-
clazz = getJdkProxyClass(getCommonClassLoader(intfs), intfs);
101+
clazz = getJdkProxyClass(classLoader, intfs);
100102
} catch (Throwable e) {
101-
if (NativeImageOptions.AllowIncompleteClasspath.getValue()) {
102-
return e;
103-
} else {
104-
throw e;
103+
try {
104+
clazz = getJdkProxyClass(getCommonClassLoader(intfs), intfs);
105+
} catch (Throwable e2) {
106+
if (NativeImageOptions.AllowIncompleteClasspath.getValue()) {
107+
return e;
108+
} else {
109+
throw e;
110+
}
105111
}
106112
}
107113

substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/proxy/hosted/DynamicProxyFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void duringSetup(DuringSetupAccess a) {
6161
DuringSetupAccessImpl access = (DuringSetupAccessImpl) a;
6262

6363
ImageClassLoader imageClassLoader = access.getImageClassLoader();
64-
DynamicProxySupport dynamicProxySupport = new DynamicProxySupport();
64+
DynamicProxySupport dynamicProxySupport = new DynamicProxySupport(imageClassLoader.getClassLoader());
6565
ImageSingletons.add(DynamicProxyRegistry.class, dynamicProxySupport);
6666
ConfigurationTypeResolver typeResolver = new ConfigurationTypeResolver("resource configuration", imageClassLoader, NativeImageOptions.AllowIncompleteClasspath.getValue());
6767
ProxyRegistry proxyRegistry = new ProxyRegistry(typeResolver, dynamicProxySupport, imageClassLoader);

substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/ReflectionMetadataDecoderImpl.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,12 @@ private static Executable decodeExecutable(UnsafeArrayTypeReader buf, CodeInfo i
258258
}
259259
boolean complete = (modifiers & COMPLETE_FLAG_MASK) != 0;
260260
boolean hiding = (modifiers & HIDING_FLAG_MASK) != 0;
261+
assert !(complete && hiding);
261262
modifiers &= ~COMPLETE_FLAG_MASK;
262263

263264
String name = isMethod ? decodeName(buf, info) : null;
264265
Class<?>[] parameterTypes = decodeArray(buf, Class.class, (i) -> decodeType(buf, info));
265-
Class<?> returnType = isMethod && hiding ? decodeType(buf, info) : null;
266+
Class<?> returnType = isMethod ? decodeType(buf, info) : null;
266267
if (!complete) {
267268
if (reflectOnly != hiding) {
268269
/*
@@ -282,8 +283,6 @@ private static Executable decodeExecutable(UnsafeArrayTypeReader buf, CodeInfo i
282283
return SubstrateUtil.cast(constructor, Executable.class);
283284
}
284285
}
285-
assert !hiding;
286-
returnType = isMethod ? decodeType(buf, info) : null;
287286
Class<?>[] exceptionTypes = decodeArray(buf, Class.class, (i) -> decodeType(buf, info));
288287
String signature = decodeName(buf, info);
289288
byte[] annotations = decodeByteArray(buf);

0 commit comments

Comments
 (0)