Skip to content
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

[GR-36431] Use reflection metadata for all objects #4222

Merged
merged 3 commits into from
Mar 13, 2022
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
Expand Up @@ -74,7 +74,13 @@ protected Chunk(int arrayLength) {
protected int totalSize;

public static UnsafeArrayTypeWriter create(boolean supportsUnalignedMemoryAccess) {
if (supportsUnalignedMemoryAccess) {
return create(supportsUnalignedMemoryAccess, false);
}

public static UnsafeArrayTypeWriter create(boolean supportsUnalignedMemoryAccess, boolean bigEndian) {
if (bigEndian) {
return new BigEndianUnsafeArrayTypeWriter();
} else if (supportsUnalignedMemoryAccess) {
return new UnalignedUnsafeArrayTypeWriter();
} else {
return new AlignedUnsafeArrayTypeWriter();
Expand Down Expand Up @@ -287,3 +293,35 @@ protected void putS8(long value, Chunk chunk, long offset) {
UNSAFE.putByte(chunk.data, offset + 7, (byte) (value >> 56));
}
}

final class BigEndianUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter {
private static final Unsafe UNSAFE = getUnsafe();

@Override
protected void putS2(long value, Chunk chunk, long offset) {
assert TypeConversion.isS2(value);
UNSAFE.putByte(chunk.data, offset + 0, (byte) (value >> 8));
UNSAFE.putByte(chunk.data, offset + 1, (byte) (value >> 0));
}

@Override
protected void putS4(long value, Chunk chunk, long offset) {
assert TypeConversion.isS4(value);
UNSAFE.putByte(chunk.data, offset + 0, (byte) (value >> 24));
UNSAFE.putByte(chunk.data, offset + 1, (byte) (value >> 16));
UNSAFE.putByte(chunk.data, offset + 2, (byte) (value >> 8));
UNSAFE.putByte(chunk.data, offset + 3, (byte) (value >> 0));
}

@Override
protected void putS8(long value, Chunk chunk, long offset) {
UNSAFE.putByte(chunk.data, offset + 0, (byte) (value >> 56));
UNSAFE.putByte(chunk.data, offset + 1, (byte) (value >> 48));
UNSAFE.putByte(chunk.data, offset + 2, (byte) (value >> 40));
UNSAFE.putByte(chunk.data, offset + 3, (byte) (value >> 32));
UNSAFE.putByte(chunk.data, offset + 4, (byte) (value >> 24));
UNSAFE.putByte(chunk.data, offset + 5, (byte) (value >> 16));
UNSAFE.putByte(chunk.data, offset + 6, (byte) (value >> 8));
UNSAFE.putByte(chunk.data, offset + 7, (byte) (value >> 0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,12 @@ private static LocationIdentity getCacheLocation(CoreProviders providers, JavaKi
if (innerClasses == null || innerClasses.length == 0) {
throw GraalError.shouldNotReachHere("Inner classes must exist");
}
return new FieldLocationIdentity(providers.getMetaAccess().lookupJavaField(innerClasses[0].getDeclaredField("cache")));
for (Class<?> innerClass : innerClasses) {
if (innerClass.getName().endsWith("Cache")) {
return new FieldLocationIdentity(providers.getMetaAccess().lookupJavaField(innerClass.getDeclaredField("cache")));
}
}
throw GraalError.shouldNotReachHere("No cache inner class found");
} catch (Throwable e) {
throw GraalError.shouldNotReachHere(e);
}
Expand Down
10 changes: 5 additions & 5 deletions docs/reference-manual/native-image/BuildOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ To reduce overhead, please ensure that the classpath only contains entries that

#### <a name="glossary-reflection-registrations"></a>Reflection Registrations
The number of classes, fields, and methods that are registered for reflection.
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)).
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)).

#### <a name="glossary-jni-access-registrations"></a>JNI Access Registrations
The number of classes, fields, and methods that are registered for [JNI][doc_jni] access.
Expand Down Expand Up @@ -136,16 +136,16 @@ Therefore, reducing the number of [reachable methods](#glossary-reachability) al
The image heap contains reachable objects such as static application data, metadata, and `byte[]` for different purposes.

##### <a name="glossary-general-heap-data"></a>General Heap Data Stored in `byte[]`
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).
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).
Therefore, this can also include `byte[]` objects from application code.

##### <a name="glossary-code-metadata"></a>Code Metadata Stored in `byte[]`
The total size of all `byte[]` objects used for metadata for the [code area](#glossary-code-area).
Therefore, reducing the number of [reachable methods](#glossary-reachability) also reduces the size of this metadata.

##### <a name="glossary-method-metadata"></a>Method Metadata Stored in `byte[]`
The total size of all `byte[]` objects used for method metadata, a type of reflection metadata.
To reduce the amount of method metadata, reduce the number of [classes registered for reflection](#glossary-reflection-classes).
##### <a name="glossary-reflection-metadata"></a>Reflection Metadata Stored in `byte[]`
The total size of all `byte[]` objects used for reflection metadata, including class, field, method and constructor data.
To reduce the amount of reflection metadata, reduce the number of [elements registered for reflection](#glossary-reflection-registrations).

##### <a name="glossary-graph-encodings"></a>Graph Encodings Stored in `byte[]`
The total size of all `byte[]` objects used for graph encodings.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, 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 Expand Up @@ -47,6 +47,8 @@
import java.util.Collections;
import java.util.List;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.function.CLibrary;

/**
Expand All @@ -58,6 +60,7 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Platforms(Platform.HOSTED_ONLY.class)
public @interface CContext {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,36 @@
*/
package org.graalvm.nativeimage.impl;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

public interface RuntimeReflectionSupport extends ReflectionRegistry {
// specific to java.lang.reflect reflection
Set<Executable> getQueriedOnlyMethods();
Map<Class<?>, Set<Class<?>>> getReflectionInnerClasses();

Set<Field> getReflectionFields();

Set<Executable> getReflectionExecutables();

Object getAccessor(Executable method);

/*
* Returns the methods that shadow a superclass method registered for reflection, to be excluded
* from reflection queries.
*/
Set<?> getHidingMethods();
Set<?> getHidingReflectionMethods();

Object[] getRecordComponents(Class<?> type);

void registerHeapDynamicHub(Object hub);

Set<?> getHeapDynamicHubs();

void registerHeapReflectionObject(AccessibleObject object);

Set<AccessibleObject> getHeapReflectionObjects();

int getReflectionClassesCount();

Expand Down
2 changes: 2 additions & 0 deletions substratevm/mx.substratevm/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@
"sun.invoke.util",
"sun.net",
"sun.reflect.annotation",
"sun.reflect.generics.factory",
"sun.reflect.generics.reflectiveObjects",
"sun.reflect.generics.repository",
"sun.reflect.generics.tree",
"sun.security.jca",
"sun.security.ssl",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ protected final void scanField(AnalysisField field, JavaConstant receiver, ScanR
throw AnalysisError.shouldNotReachHere("Could not find field " + field.format("%H.%n") +
(receiver == null ? "" : " on " + constantType(bb, receiver).toJavaName()) +
System.lineSeparator() + backtrace);
} else if (fieldValue.getJavaKind() == JavaKind.Illegal) {
/* The value is not available yet */
return;
}

if (fieldValue.getJavaKind() == JavaKind.Object && bb.getHostVM().isRelocatedPointer(constantAsObject(bb, fieldValue))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ private boolean notifyAnalysis(JavaConstant array, AnalysisType arrayType, JavaC
return analysisModified;
}

void onObjectReachable(ImageHeapObject imageHeapObject) {
protected void onObjectReachable(ImageHeapObject imageHeapObject) {
AnalysisType objectType = metaAccess.lookupJavaType(imageHeapObject.getObject());
imageHeap.add(objectType, imageHeapObject);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,8 +720,9 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String ol
}
};

@SuppressWarnings("unused")//
@APIOption(name = "configure-reflection-metadata")//
@Option(help = "Enable runtime instantiation of reflection objects for non-invoked methods.", type = OptionType.Expert)//
@Option(help = "Enable runtime instantiation of reflection objects for non-invoked methods.", type = OptionType.Expert, deprecated = true)//
public static final HostedOptionKey<Boolean> ConfigureReflectionMetadata = new HostedOptionKey<>(true);

@Option(help = "Include a list of methods included in the image for runtime inspection.", type = OptionType.Expert)//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public void addToReferenceMapSize(long size) {
}

public static final class Encoders {
final FrequencyEncoder<JavaConstant> objectConstants;
public final FrequencyEncoder<JavaConstant> objectConstants;
public final FrequencyEncoder<Class<?>> sourceClasses;
public final FrequencyEncoder<String> sourceMethodNames;
final FrequencyEncoder<String> names;
Expand Down
Loading