Skip to content

[GR-64061] Footprint improvements in Native Image Builder. #11116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -119,6 +119,8 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Boolean> reachableInCurrentLayerUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Boolean.class, "reachableInCurrentLayer");

public static final AnalysisMethod[] EMPTY_ARRAY = new AnalysisMethod[0];

public record Signature(String name, AnalysisType[] parameterTypes) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav

private static final AtomicReferenceFieldUpdater<AnalysisType, Object> RESOLVED_METHODS_UPDATER = AtomicReferenceFieldUpdater.newUpdater(AnalysisType.class, Object.class, "resolvedMethods");

public static final AnalysisType[] EMPTY_ARRAY = new AnalysisType[0];

protected final AnalysisUniverse universe;
private final ResolvedJavaType wrapped;
private final String qualifiedName;
Expand Down Expand Up @@ -360,7 +362,7 @@ private AnalysisType[] convertTypes(ResolvedJavaType[] originalTypes) {
}
result.add(universe.lookup(originalType));
}
return result.toArray(new AnalysisType[result.size()]);
return result.toArray(AnalysisType.EMPTY_ARRAY);
}

public AnalysisType getArrayClass(int dim) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -471,7 +471,7 @@ public AnalysisMethod[] lookup(JavaMethod[] inputs) {
}
}
}
return result.toArray(new AnalysisMethod[result.size()]);
return result.toArray(AnalysisMethod.EMPTY_ARRAY);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import com.oracle.svm.hosted.meta.HostedMethod;

class CodeBreakdownProvider {
private final Map<String, Long> codeBreakdown;
private Map<String, Long> codeBreakdown;

CodeBreakdownProvider(Collection<CompileTask> compilationTasks) {
Map<String, Long> nameToSizeMap = new HashMap<>();
Expand All @@ -60,8 +60,17 @@ class CodeBreakdownProvider {
codeBreakdown = Collections.unmodifiableMap(nameToSizeMap);
}

public static Map<String, Long> get() {
return ImageSingletons.lookup(CodeBreakdownProvider.class).codeBreakdown;
/**
* Provides the code breakdown as map from name to size, and clears the cache to avoid memory
* footprint.
*
* @return the code breakdown
*/
public static Map<String, Long> getAndClear() {
CodeBreakdownProvider singleton = ImageSingletons.lookup(CodeBreakdownProvider.class);
Map<String, Long> map = singleton.codeBreakdown;
singleton.codeBreakdown = null;
return map;
}

private static String findJARFile(Class<?> javaClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ private void printBreakdowns() {
return;
}
l().printLineSeparator();
Map<String, Long> codeBreakdown = CodeBreakdownProvider.get();
Map<String, Long> codeBreakdown = CodeBreakdownProvider.getAndClear();
Iterator<Entry<String, Long>> packagesBySize = codeBreakdown.entrySet().stream()
.sorted(Entry.comparingByValue(Comparator.reverseOrder())).iterator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,9 @@ private AnnotationValue[][] getParameterAnnotationDataFromRoot(Executable rootEl
ByteBuffer buf = ByteBuffer.wrap(rawParameterAnnotations);
try {
int numParameters = buf.get() & 0xFF;
if (numParameters == 0) {
return NO_PARAMETER_ANNOTATIONS;
}
AnnotationValue[][] parameterAnnotations = new AnnotationValue[numParameters][];
for (int i = 0; i < numParameters; i++) {
List<AnnotationValue> parameterAnnotationList = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static CEntryPointData createCustomUnpublished() {
private static CEntryPointData create(CEntryPoint annotation, CEntryPointOptions options, Supplier<String> alternativeNameSupplier) {
String annotatedName = annotation.name();
Class<? extends Function<String, String>> nameTransformation = DEFAULT_NAME_TRANSFORMATION;
String documentation = String.join(System.lineSeparator(), annotation.documentation());
String documentation = annotation.documentation().length == 0 ? "" : String.join(System.lineSeparator(), annotation.documentation());
CEntryPoint.Builtin builtin = annotation.builtin();
Class<?> prologue = DEFAULT_PROLOGUE;
Class<?> prologueBailout = DEFAULT_PROLOGUE_BAILOUT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public void aggregateMethods(Collection<AnalysisMethod> methods) {
}
MethodAggregator visitor = new MethodAggregator(aggregation, assertionErrorConstructorList);
AnalysisMethodCalleeWalker walker = new AnalysisMethodCalleeWalker();
for (AnalysisMethod method : aggregation.keySet().toArray(new AnalysisMethod[0])) {
for (AnalysisMethod method : aggregation.keySet().toArray(AnalysisMethod.EMPTY_ARRAY)) {
walker.walkMethod(method, visitor);
}
calleeToCallerMap = Collections.unmodifiableMap(aggregation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,8 @@ public void addRecordComponentsLookupError(HostedType declaringClass, Throwable
}

private static HostedType[] getParameterTypes(HostedMethod method) {
HostedType[] parameterTypes = new HostedType[method.getSignature().getParameterCount(false)];
int len = method.getSignature().getParameterCount(false);
HostedType[] parameterTypes = len == 0 ? HostedType.EMPTY_ARRAY : new HostedType[len];
for (int i = 0; i < parameterTypes.length; ++i) {
parameterTypes[i] = method.getSignature().getParameterType(i);
}
Expand All @@ -737,7 +738,7 @@ private static String[] getParameterTypeNames(HostedMethod method) {

private static HostedType[] getExceptionTypes(MetaAccessProvider metaAccess, Executable reflectMethod) {
Class<?>[] exceptionClasses = reflectMethod.getExceptionTypes();
HostedType[] exceptionTypes = new HostedType[exceptionClasses.length];
HostedType[] exceptionTypes = exceptionClasses.length == 0 ? HostedType.EMPTY_ARRAY : new HostedType[exceptionClasses.length];
for (int i = 0; i < exceptionClasses.length; ++i) {
exceptionTypes[i] = (HostedType) metaAccess.lookupJavaType(exceptionClasses[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public NativeImageHeapWriter(NativeImageHeap heap, ImageHeapLayoutInfo heapLayou
public long writeHeap(DebugContext debug, RelocatableBuffer buffer) {
try (Indent perHeapIndent = debug.logAndIndent("NativeImageHeap.writeHeap:")) {
for (ObjectInfo info : heap.getObjects()) {
assert !heap.isBlacklisted(info.getObject());
assert !heap.isBlacklisted(info.getObject()) : "Backlisted object: " + info.getObject();
if (info.getConstant().isWrittenInPreviousLayer()) {
/*
* Base layer constants already written in the base layer heap are only added to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public int getArrayDimension() {

@Override
public HostedField[] getInstanceFields(boolean includeSuperclasses) {
return new HostedField[0];
return HostedField.EMPTY_ARRAY;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
*/
public class HostedField extends HostedElement implements OriginalFieldProvider, SharedField, WrappedJavaField {

static final int LOC_UNMATERIALIZED_STATIC_CONSTANT = -10;

public static final HostedField[] EMPTY_ARRAY = new HostedField[0];

public final AnalysisField wrapped;

private final HostedType holder;
Expand All @@ -51,8 +55,6 @@ public class HostedField extends HostedElement implements OriginalFieldProvider,
protected int location;
private int installedLayerNum;

static final int LOC_UNMATERIALIZED_STATIC_CONSTANT = -10;

public HostedField(AnalysisField wrapped, HostedType holder, HostedType type) {
this.wrapped = wrapped;
this.holder = holder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
*/
public class HostedInterface extends HostedType {

public static final HostedInterface[] EMPTY_ARRAY = new HostedInterface[0];

public HostedInterface(HostedUniverse universe, AnalysisType wrapped, JavaKind kind, JavaKind storageKind, HostedInterface[] interfaces) {
super(universe, wrapped, kind, storageKind, null, interfaces);
}
Expand Down Expand Up @@ -87,6 +89,6 @@ public int getArrayDimension() {

@Override
public HostedField[] getInstanceFields(boolean includeSuperclasses) {
return new HostedField[0];
return HostedField.EMPTY_ARRAY;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public class HostedPrimitiveType extends HostedType {

public HostedPrimitiveType(HostedUniverse universe, AnalysisType wrapped, JavaKind kind, JavaKind storageKind) {
super(universe, wrapped, kind, storageKind, null, new HostedInterface[0]);
super(universe, wrapped, kind, storageKind, null, HostedInterface.EMPTY_ARRAY);
}

@Override
Expand Down Expand Up @@ -81,7 +81,7 @@ public int getArrayDimension() {

@Override
public HostedField[] getInstanceFields(boolean includeSuperclasses) {
return new HostedField[0];
return HostedField.EMPTY_ARRAY;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ public HostedType optionalLookup(JavaType type) {
}

public HostedType[] optionalLookup(JavaType... javaTypes) {
HostedType[] result = new HostedType[javaTypes.length];
HostedType[] result = new HostedType[javaTypes.length]; // EMPTY_ARRAY failing here
for (int i = 0; i < javaTypes.length; ++i) {
result[i] = optionalLookup(javaTypes[i]);
if (result[i] == null) {
Expand Down Expand Up @@ -421,7 +421,7 @@ public HostedMethod optionalLookup(JavaMethod method) {
}

public HostedMethod[] lookup(JavaMethod[] inputs) {
HostedMethod[] result = new HostedMethod[inputs.length];
HostedMethod[] result = new HostedMethod[inputs.length]; // EMPTY_ARRAY failing here
for (int i = 0; i < result.length; i++) {
result[i] = lookup(inputs[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
import java.util.stream.Collectors;

import org.graalvm.nativeimage.ImageInfo;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.function.CEntryPointLiteral;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.function.CFunctionPointer;
Expand Down Expand Up @@ -119,6 +121,7 @@

public class UniverseBuilder {

@Platforms(Platform.HOSTED_ONLY.class) private static final CFunctionPointer[] EMPTY_ARRAY = new CFunctionPointer[0];
private final AnalysisUniverse aUniverse;
private final AnalysisMetaAccess aMetaAccess;
private final HostedUniverse hUniverse;
Expand Down Expand Up @@ -227,7 +230,7 @@ private HostedType makeType(AnalysisType aType) {
assert !typeName.contains("/hosted/meta/") : "Hosted meta object in image " + typeName;

AnalysisType[] aInterfaces = aType.getInterfaces();
HostedInterface[] sInterfaces = new HostedInterface[aInterfaces.length];
HostedInterface[] sInterfaces = aInterfaces.length == 0 ? HostedInterface.EMPTY_ARRAY : new HostedInterface[aInterfaces.length];
for (int i = 0; i < aInterfaces.length; i++) {
sInterfaces[i] = (HostedInterface) makeType(aInterfaces[i]);
}
Expand Down Expand Up @@ -469,7 +472,7 @@ public static boolean isKnownImmutableType(Class<?> clazz) {
private void layoutInstanceFields(int numTypeCheckSlots) {
BitSet usedBytes = new BitSet();
usedBytes.set(0, ConfigurationValues.getObjectLayout().getFirstFieldOffset());
layoutInstanceFields(hUniverse.getObjectClass(), new HostedField[0], usedBytes, numTypeCheckSlots);
layoutInstanceFields(hUniverse.getObjectClass(), HostedField.EMPTY_ARRAY, usedBytes, numTypeCheckSlots);
}

private static boolean mustReserveArrayFields(HostedInstanceClass clazz) {
Expand Down Expand Up @@ -640,7 +643,7 @@ private void layoutInstanceFields(HostedInstanceClass clazz, HostedField[] super
clazz.setIdentityHashOffset(offset);
}

clazz.instanceFieldsWithoutSuper = allFields.toArray(new HostedField[0]);
clazz.instanceFieldsWithoutSuper = allFields.toArray(HostedField.EMPTY_ARRAY);
clazz.firstInstanceFieldOffset = firstInstanceFieldOffset;
clazz.afterFieldsOffset = afterFieldsOffset;
clazz.instanceSize = layout.alignUp(afterFieldsOffset);
Expand Down Expand Up @@ -840,13 +843,12 @@ private void layoutStaticFields() {
fieldsOfTypes[typeId].add(field);
}

HostedField[] noFields = new HostedField[0];
for (HostedType type : hUniverse.getTypes()) {
List<HostedField> fieldsOfType = fieldsOfTypes[type.getTypeID()];
if (fieldsOfType != null) {
type.staticFields = fieldsOfType.toArray(new HostedField[fieldsOfType.size()]);
} else {
type.staticFields = noFields;
type.staticFields = HostedField.EMPTY_ARRAY;
}
}

Expand Down Expand Up @@ -886,7 +888,7 @@ private void collectMethodImplementations() {
for (HostedMethod method : hUniverse.methods.values()) {

// Reuse the implementations from the analysis method.
method.implementations = hUniverse.lookup(method.wrapped.collectMethodImplementations(false).toArray(new AnalysisMethod[0]));
method.implementations = hUniverse.lookup(method.wrapped.collectMethodImplementations(false).toArray(AnalysisMethod.EMPTY_ARRAY));
Arrays.sort(method.implementations, HostedUniverse.METHOD_COMPARATOR);
}
}
Expand Down Expand Up @@ -955,7 +957,7 @@ private void buildHubs() {
hub.setSharedData(layoutHelper, monitorOffset, identityHashOffset, referenceMapIndex, type.isInstantiated());

if (SubstrateOptions.useClosedTypeWorldHubLayout()) {
CFunctionPointer[] vtable = new CFunctionPointer[type.closedTypeWorldVTable.length];
CFunctionPointer[] vtable = type.closedTypeWorldVTable.length == 0 ? EMPTY_ARRAY : new CFunctionPointer[type.closedTypeWorldVTable.length];
for (int idx = 0; idx < type.closedTypeWorldVTable.length; idx++) {
/*
* We install a CodePointer in the vtable; when generating relocation info, we
Expand Down Expand Up @@ -994,7 +996,7 @@ private void buildHubs() {
typeSlotIdx += 2;
}

CFunctionPointer[] vtable = new CFunctionPointer[type.openTypeWorldDispatchTables.length];
CFunctionPointer[] vtable = type.openTypeWorldDispatchTables.length == 0 ? EMPTY_ARRAY : new CFunctionPointer[type.openTypeWorldDispatchTables.length];
for (int idx = 0; idx < type.openTypeWorldDispatchTables.length; idx++) {
/*
* We install a CodePointer in the open world vtable; when generating relocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ private void buildClosedTypeWorldVTables() {
if (type.isArray()) {
type.closedTypeWorldVTable = objectClass.closedTypeWorldVTable;
}
if (type.closedTypeWorldVTable == null) {
assert type.isInterface() || type.isPrimitive();
if (type.closedTypeWorldVTable == null || type.closedTypeWorldVTable.length == 0) {
assert type.isInterface() || type.isPrimitive() || type.closedTypeWorldVTable.length == 0;
type.closedTypeWorldVTable = HostedMethod.EMPTY_ARRAY;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ private void registerTypesForAnnotations(AnnotatedElement annotatedElement) {
registerTypesForAnnotation(annotation);
}
}
filteredAnnotations.put(annotatedElement, includedAnnotations.toArray(new AnnotationValue[0]));
filteredAnnotations.put(annotatedElement, includedAnnotations.toArray(NO_ANNOTATIONS));
}
}
}
Expand All @@ -974,7 +974,7 @@ private void registerTypesForParameterAnnotations(AnalysisMethod method) {
if (method != null) {
if (!filteredParameterAnnotations.containsKey(method)) {
AnnotationValue[][] parameterAnnotations = annotationExtractor.getParameterAnnotationData(method);
AnnotationValue[][] includedParameterAnnotations = new AnnotationValue[parameterAnnotations.length][];
AnnotationValue[][] includedParameterAnnotations = parameterAnnotations.length == 0 ? NO_PARAMETER_ANNOTATIONS : new AnnotationValue[parameterAnnotations.length][];
for (int i = 0; i < includedParameterAnnotations.length; ++i) {
AnnotationValue[] annotations = parameterAnnotations[i];
List<AnnotationValue> includedAnnotations = new ArrayList<>();
Expand All @@ -984,7 +984,7 @@ private void registerTypesForParameterAnnotations(AnalysisMethod method) {
registerTypesForAnnotation(annotation);
}
}
includedParameterAnnotations[i] = includedAnnotations.toArray(new AnnotationValue[0]);
includedParameterAnnotations[i] = includedAnnotations.toArray(NO_ANNOTATIONS);
}
filteredParameterAnnotations.put(method, includedParameterAnnotations);
}
Expand All @@ -1001,7 +1001,7 @@ private void registerTypesForTypeAnnotations(AnnotatedElement annotatedElement)
registerTypesForAnnotation(typeAnnotation.getAnnotationData());
}
}
filteredTypeAnnotations.put(annotatedElement, includedTypeAnnotations.toArray(new TypeAnnotationValue[0]));
filteredTypeAnnotations.put(annotatedElement, includedTypeAnnotations.toArray(NO_TYPE_ANNOTATIONS));
}
}
}
Expand Down