Skip to content

Commit faecb26

Browse files
committed
mitigate cost of HotSpotMetaAccessProvider.lookupField for classes with many fields
1 parent 0c95752 commit faecb26

File tree

2 files changed

+67
-24
lines changed

2 files changed

+67
-24
lines changed

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,8 @@ public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) {
8282
@Override
8383
public ResolvedJavaField lookupJavaField(Field reflectionField) {
8484
Class<?> fieldHolder = reflectionField.getDeclaringClass();
85-
HotSpotResolvedJavaType holder = runtime.fromClass(fieldHolder);
86-
assert holder != null : fieldHolder;
87-
ResolvedJavaField[] fields;
88-
if (Modifier.isStatic(reflectionField.getModifiers())) {
89-
fields = holder.getStaticFields();
90-
} else {
91-
fields = holder.getInstanceFields(false);
92-
}
93-
ResolvedJavaType fieldType = lookupJavaType(reflectionField.getType());
94-
for (ResolvedJavaField field : fields) {
95-
if (reflectionField.getName().equals(field.getName()) && field.getType().equals(fieldType)) {
96-
assert Modifier.isStatic(reflectionField.getModifiers()) == field.isStatic();
97-
return field;
98-
}
99-
}
100-
101-
throw new JVMCIError("unresolved field %s", reflectionField);
85+
HotSpotResolvedObjectTypeImpl holder = (HotSpotResolvedObjectTypeImpl) runtime.fromClass(fieldHolder);
86+
return holder.lookupField(reflectionField);
10287
}
10388

10489
private static int intMaskRight(int n) {

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.ArrayList;
4040
import java.util.HashMap;
4141
import java.util.List;
42+
import java.util.Map;
4243

4344
import jdk.vm.ci.common.JVMCIError;
4445
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
@@ -50,6 +51,7 @@
5051
import jdk.vm.ci.meta.JavaConstant;
5152
import jdk.vm.ci.meta.JavaKind;
5253
import jdk.vm.ci.meta.JavaType;
54+
import jdk.vm.ci.meta.MetaUtil;
5355
import jdk.vm.ci.meta.ResolvedJavaField;
5456
import jdk.vm.ci.meta.ResolvedJavaMethod;
5557
import jdk.vm.ci.meta.ResolvedJavaRecordComponent;
@@ -744,6 +746,51 @@ protected HotSpotResolvedObjectTypeImpl getArrayType() {
744746
return runtime().compilerToVm.getArrayType((char) 0, this);
745747
}
746748

749+
/**
750+
* Map to mitigate exponential cost of {@link #lookupField} for classes with many fields.
751+
*/
752+
Map<FieldInfo.Key, Integer> fieldInfoMap;
753+
754+
/**
755+
* Classes with more than this number of fields will use {@link #fieldInfoMap}
756+
* in {@link #lookupField(Field)}.
757+
*/
758+
private static final int FIELD_INFO_MAP_THRESHOLD = 1024;
759+
760+
/**
761+
* Support for {@link HotSpotMetaAccessProvider#lookupJavaField(Field)}.
762+
*/
763+
HotSpotResolvedJavaField lookupField(Field reflectionField) {
764+
FieldInfo[] fields = getFieldInfo();
765+
String name = reflectionField.getName();
766+
String sig = MetaUtil.toInternalName(reflectionField.getType().getName());
767+
boolean isStatic = Modifier.isStatic(reflectionField.getModifiers());
768+
FieldInfo.Key key = new FieldInfo.Key(name, sig, isStatic);
769+
if (fields.length > FIELD_INFO_MAP_THRESHOLD) {
770+
if (fieldInfoMap == null) {
771+
Map<FieldInfo.Key, Integer> map = new HashMap<>(fields.length);
772+
for (int index = 0; index < fields.length; index++) {
773+
FieldInfo fi = fields[index];
774+
map.put(FieldInfo.Key.from(fi, this), index);
775+
}
776+
fieldInfoMap = map;
777+
}
778+
Integer index = fieldInfoMap.get(key);
779+
if (index != null) {
780+
FieldInfo fi = fields[index];
781+
return createField(fi.getType(this), fi.offset(), fi.classfileFlags(), fi.internalFlags(), index);
782+
}
783+
} else {
784+
for (int index = 0; index < fields.length; index++) {
785+
FieldInfo fi = fields[index];
786+
if (FieldInfo.Key.from(fi, this).equals(key)) {
787+
return createField(fi.getType(this), fi.offset(), fi.classfileFlags(), fi.internalFlags(), index);
788+
}
789+
}
790+
}
791+
throw new JVMCIError("unresolved field %s", reflectionField);
792+
}
793+
747794
/**
748795
* This class represents the field information for one field contained in the fields array of an
749796
* {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class.
@@ -755,8 +802,18 @@ protected HotSpotResolvedObjectTypeImpl getArrayType() {
755802
* @param internalFlags field's internal flags (from the VM)
756803
* @param initializerIndex field's initial value index in the constant pool
757804
*/
758-
record FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags,
759-
int initializerIndex) {
805+
record FieldInfo(int nameIndex,
806+
int signatureIndex,
807+
int offset,
808+
int classfileFlags,
809+
int internalFlags,
810+
int initializerIndex) {
811+
812+
record Key(String name, String signature, boolean isStatic) {
813+
static Key from(FieldInfo fi, HotSpotResolvedObjectTypeImpl holder) {
814+
return new FieldInfo.Key(fi.getName(holder), fi.getSignature(holder), fi.isStatic());
815+
}
816+
}
760817

761818
/**
762819
* Returns the name of this field as a {@link String}. If the field is an internal field the
@@ -880,8 +937,9 @@ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSp
880937
int resultCount = 0;
881938
int index;
882939

883-
for (index = 0; index < getFieldInfo().length; index++) {
884-
if (getFieldInfo(index).isStatic() == retrieveStaticFields) {
940+
FieldInfo[] fieldInfo = getFieldInfo();
941+
for (index = 0; index < fieldInfo.length; index++) {
942+
if (fieldInfo[index].isStatic() == retrieveStaticFields) {
885943
resultCount++;
886944
}
887945
}
@@ -902,8 +960,8 @@ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSp
902960
// but the array of fields to be returned must be sorted by increasing offset
903961
// This code populates the array, then applies the sorting function
904962
int resultIndex = prependLength;
905-
for (int i = 0; i < getFieldInfo().length; ++i) {
906-
FieldInfo field = getFieldInfo(i);
963+
for (int i = 0; i < fieldInfo.length; ++i) {
964+
FieldInfo field = fieldInfo[i];
907965
if (field.isStatic() == retrieveStaticFields) {
908966
int offset = field.offset();
909967
HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.classfileFlags(), field.internalFlags(), i);
@@ -1058,7 +1116,7 @@ private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expec
10581116
// @formatter:off
10591117
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN &&
10601118
expectedEntryKind.isPrimitive() &&
1061-
!expectedEntryKind.equals(JavaKind.Void) &&
1119+
!expectedEntryKind.equals(jdk.vm.ci.meta.JavaKind.Void) &&
10621120
field.getJavaKind().isPrimitive()) {
10631121
resolvedFieldOffset +=
10641122
field.getJavaKind().getByteCount() -

0 commit comments

Comments
 (0)