Skip to content

Commit 935bb28

Browse files
committed
[GR-60069] Field layout for Crema.
PullRequest: graal/21484
2 parents 342fa1d + d486ae9 commit 935bb28

26 files changed

+844
-202
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpMetadata.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,10 @@ public boolean initialize() {
238238
Heap.getHeap().walkImageHeapObjects(computeHubDataVisitor);
239239
Metaspace.singleton().walkObjects(computeHubDataVisitor);
240240

241-
/*
242-
* Classes that are loaded at runtime don't have any declared fields at the moment. This
243-
* needs to be changed once GR-60069 is merged.
244-
*/
245241
for (int i = TypeIDs.singleton().getFirstRuntimeTypeId(); i < classInfoCount; i++) {
246242
ClassInfo classInfo = getClassInfo(i);
247243
if (ClassInfoAccess.isValid(classInfo)) {
244+
/* GR-69330 */
248245
classInfo.setStaticFieldCount(0);
249246
classInfo.setInstanceFieldCount(0);
250247
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,9 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
482482
int[] interfaceHashTableHeapArray,
483483
int openTypeWorldInterfaceHashParam,
484484
int vTableEntries,
485-
int afterFieldsOffset, boolean valueBased) {
485+
int[] declaredInstanceReferenceFieldOffsets,
486+
int afterFieldsOffset,
487+
boolean valueBased) {
486488
VMError.guarantee(RuntimeClassLoading.isSupported());
487489

488490
ReferenceType referenceType = ReferenceType.computeReferenceType(DynamicHub.toClass(superHub));
@@ -540,7 +542,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
540542

541543
boolean needsMonitorOffset = !valueBased;
542544
if (needsMonitorOffset) {
543-
// GR-60069 could look for gaps
545+
// GR-69304 could look for gaps
544546
int size = ol.getReferenceSize();
545547
int bits = size - 1;
546548
int alignmentAdjust = ((instanceSize + bits) & ~bits) - instanceSize;
@@ -551,7 +553,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
551553
if (ol.isIdentityHashFieldInObjectHeader()) {
552554
identityHashOffset = ol.getObjectHeaderIdentityHashOffset();
553555
} else if (ol.isIdentityHashFieldAtTypeSpecificOffset() || ol.isIdentityHashFieldOptional()) {
554-
// GR-60069 could look for gaps
556+
// GR-69304 could look for gaps
555557
int bits = Integer.BYTES - 1;
556558
int alignmentAdjust = ((instanceSize + bits) & ~bits) - instanceSize;
557559
identityHashOffset = instanceSize + alignmentAdjust;
@@ -590,7 +592,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
590592
DynamicHub hub = Metaspace.singleton().allocateDynamicHub(vTableEntries);
591593
int[] openTypeWorldTypeCheckSlots = Metaspace.singleton().copyToMetaspace(typeCheckSlotsHeapArray);
592594
int[] openTypeWorldInterfaceHashTable = Metaspace.singleton().copyToMetaspace(interfaceHashTableHeapArray);
593-
int referenceMapCompressedOffset = RuntimeInstanceReferenceMapSupport.singleton().getOrCreateReferenceMap(superHub);
595+
int referenceMapCompressedOffset = RuntimeInstanceReferenceMapSupport.singleton().getOrCreateReferenceMap(superHub, declaredInstanceReferenceFieldOffsets);
594596

595597
/* Write fields in defining order. */
596598
DynamicHubOffsets dynamicHubOffsets = DynamicHubOffsets.singleton();

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,11 @@ public static RuntimeInstanceReferenceMapSupport singleton() {
7171
* @return a compressed offset, relative to the heap base, that points to an
7272
* {@link InstanceReferenceMap}.
7373
*/
74-
public int getOrCreateReferenceMap(DynamicHub superHub, FieldInfo... declaredInstanceFields) {
74+
public int getOrCreateReferenceMap(DynamicHub superHub, int... declaredInstanceReferenceFieldsOffsets) {
7575
/* Create a bitmap and mark where there are declared object fields. */
7676
SubstrateReferenceMap map = new SubstrateReferenceMap();
77-
for (var field : declaredInstanceFields) {
78-
if (field.hasObjectType()) {
79-
map.markReferenceAtOffset(field.offset(), true);
80-
}
77+
for (int offset : declaredInstanceReferenceFieldsOffsets) {
78+
map.markReferenceAtOffset(offset, true);
8179
}
8280

8381
/* If there are no declared object fields, reuse the reference map from the super class. */
@@ -122,10 +120,6 @@ private static int toCompressedOffset(byte[] metaspaceRefMapArray) {
122120
return InstanceReferenceMapEncoder.computeReferenceMapCompressedOffset(metaspaceMap);
123121
}
124122

125-
/* Remove once GR-60069 is merged. */
126-
public record FieldInfo(int offset, boolean hasObjectType) {
127-
}
128-
129123
private record ReferenceMapHolder(byte[] refMap) {
130124
@Override
131125
public int hashCode() {

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
*/
2525
package com.oracle.svm.core.hub;
2626

27+
import java.lang.reflect.Constructor;
28+
import java.lang.reflect.Field;
29+
import java.lang.reflect.Method;
30+
import java.lang.reflect.Modifier;
31+
import java.lang.reflect.RecordComponent;
32+
import java.util.ArrayList;
33+
2734
import com.oracle.svm.core.configure.RuntimeConditionSet;
2835
import com.oracle.svm.core.hub.crema.CremaResolvedJavaField;
2936
import com.oracle.svm.core.hub.crema.CremaResolvedJavaMethod;
@@ -36,13 +43,6 @@
3643
import jdk.vm.ci.meta.ResolvedJavaType;
3744
import jdk.vm.ci.meta.UnresolvedJavaType;
3845

39-
import java.lang.reflect.Constructor;
40-
import java.lang.reflect.Field;
41-
import java.lang.reflect.Method;
42-
import java.lang.reflect.Modifier;
43-
import java.lang.reflect.RecordComponent;
44-
import java.util.ArrayList;
45-
4646
/**
4747
* Instances of this class are used to represent the reflection metadata for Dynamic hubs loaded at
4848
* runtime. Note, the use of the term 'Runtime' is not to be confused with e.g.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/crema/CremaSupport.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626

2727
import java.util.List;
2828

29-
import com.oracle.svm.core.hub.DynamicHub;
3029
import org.graalvm.nativeimage.ImageSingletons;
3130
import org.graalvm.nativeimage.Platform;
3231
import org.graalvm.nativeimage.Platforms;
3332

33+
import com.oracle.svm.core.hub.DynamicHub;
3434
import com.oracle.svm.espresso.classfile.ParserKlass;
3535

3636
import jdk.vm.ci.meta.JavaType;
@@ -47,6 +47,10 @@ interface CremaDispatchTable {
4747
int vtableLength();
4848

4949
int itableLength(Class<?> iface);
50+
51+
int afterFieldsOffset(int superAfterFieldsOffset);
52+
53+
int[] getDeclaredInstanceReferenceFieldOffsets();
5054
}
5155

5256
CremaDispatchTable getDispatchTable(ParserKlass parsed, Class<?> superClass, List<Class<?>> superInterfaces);
@@ -63,6 +67,8 @@ interface CremaDispatchTable {
6367

6468
Class<?> resolveOrNull(JavaType unresolvedJavaType, ResolvedJavaType accessingClass);
6569

70+
Class<?> findLoadedClass(JavaType unresolvedJavaType, ResolvedJavaType accessingClass);
71+
6672
static CremaSupport singleton() {
6773
return ImageSingletons.lookup(CremaSupport.class);
6874
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/registry/AbstractRuntimeClassRegistry.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
import com.oracle.svm.espresso.classfile.ClassfileStream;
5656
import com.oracle.svm.espresso.classfile.ParserConstantPool;
5757
import com.oracle.svm.espresso.classfile.ParserException;
58-
import com.oracle.svm.espresso.classfile.ParserField;
5958
import com.oracle.svm.espresso.classfile.ParserKlass;
6059
import com.oracle.svm.espresso.classfile.ParserMethod;
6160
import com.oracle.svm.espresso.classfile.attributes.Attribute;
@@ -394,15 +393,7 @@ private Class<?> createClass(ParserKlass parsed, ClassDefinitionInfo info, Symbo
394393
afterFieldsOffset = 0;
395394
} else {
396395
int superAfterFieldsOffset = CremaSupport.singleton().getAfterFieldsOffset(superHub);
397-
// GR-60069: field layout
398-
int numDeclaredInstanceFields = 0;
399-
for (ParserField field : parsed.getFields()) {
400-
if (!field.isStatic()) {
401-
numDeclaredInstanceFields += 1;
402-
}
403-
}
404-
assert numDeclaredInstanceFields == 0;
405-
afterFieldsOffset = Math.toIntExact(superAfterFieldsOffset);
396+
afterFieldsOffset = dispatchTable.afterFieldsOffset(superAfterFieldsOffset);
406397
}
407398
boolean isValueBased = (parsed.getFlags() & ACC_VALUE_BASED) != 0;
408399

@@ -414,7 +405,8 @@ private Class<?> createClass(ParserKlass parsed, ClassDefinitionInfo info, Symbo
414405
DynamicHub hub = DynamicHub.allocate(externalName, superHub, interfacesEncoding, null,
415406
sourceFile, modifiers, flags, getClassLoader(), simpleBinaryName, module, enclosingClass, classSignature,
416407
typeID, interfaceID, numClassTypes, typeIDDepth, numIterableInterfaces, openTypeWorldTypeCheckSlots, openTypeWorldInterfaceHashTable, openTypeWorldInterfaceHashParam,
417-
dispatchTableLength, afterFieldsOffset, isValueBased);
408+
dispatchTableLength,
409+
dispatchTable.getDeclaredInstanceReferenceFieldOffsets(), afterFieldsOffset, isValueBased);
418410

419411
CremaSupport.singleton().fillDynamicHubInfo(hub, dispatchTable, transitiveSuperInterfaces, iTableStartingIndices);
420412

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaMethodAccess.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242

4343
public interface CremaMethodAccess extends WithModifiers, MethodAccess<InterpreterResolvedJavaType, InterpreterResolvedJavaMethod, InterpreterResolvedJavaField> {
4444
static LineNumberTable toJVMCI(LineNumberTableAttribute parserTable) {
45+
if (parserTable == LineNumberTableAttribute.EMPTY) {
46+
return null;
47+
}
4548
List<LineNumberTableAttribute.Entry> entries = parserTable.getEntries();
4649
int[] bcis = new int[entries.size()];
4750
int[] lineNumbers = new int[entries.size()];
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.interpreter.metadata;
26+
27+
import com.oracle.svm.core.hub.DynamicHub;
28+
import com.oracle.svm.core.hub.crema.CremaResolvedJavaField;
29+
import com.oracle.svm.core.hub.crema.CremaSupport;
30+
import com.oracle.svm.espresso.classfile.ParserField;
31+
32+
import jdk.vm.ci.meta.JavaType;
33+
import jdk.vm.ci.meta.UnresolvedJavaType;
34+
35+
public class CremaResolvedJavaFieldImpl extends InterpreterResolvedJavaField implements CremaResolvedJavaField {
36+
public static final CremaResolvedJavaFieldImpl[] EMPTY_ARRAY = new CremaResolvedJavaFieldImpl[0];
37+
38+
CremaResolvedJavaFieldImpl(InterpreterResolvedObjectType declaringClass, ParserField f, int offset) {
39+
super(f.getName(), f.getType(), f.getFlags(),
40+
/*- resolvedType */ null,
41+
declaringClass,
42+
offset,
43+
/*- constantValue */ null,
44+
/*- isWordStorage */ false);
45+
}
46+
47+
public static CremaResolvedJavaFieldImpl createAtRuntime(InterpreterResolvedObjectType declaringClass, ParserField f, int offset) {
48+
return new CremaResolvedJavaFieldImpl(declaringClass, f, offset);
49+
}
50+
51+
@Override
52+
public JavaType getType() {
53+
/*
54+
* For fields created at build-time, the type is set if it is available. We explicitly do
55+
* not want to trigger field type resolution at build-time.
56+
*
57+
* If the resolvedType is null, the type was not included in the image. If we were to
58+
* eagerly create a ResolvedJavaType for it, we would force it back in.
59+
*/
60+
if (resolvedType == null) {
61+
UnresolvedJavaType unresolvedJavaType = UnresolvedJavaType.create(getSymbolicType().toString());
62+
/*
63+
* This should not trigger actual class loading. Instead, we query the loader registry
64+
* for an already loaded class.
65+
*/
66+
Class<?> cls = CremaSupport.singleton().findLoadedClass(unresolvedJavaType, getDeclaringClass());
67+
if (cls == null) {
68+
// Not loaded: return the unresolved type
69+
return unresolvedJavaType;
70+
}
71+
resolvedType = (InterpreterResolvedJavaType) DynamicHub.fromClass(cls).getInterpreterType();
72+
}
73+
return resolvedType;
74+
}
75+
76+
@Override
77+
public InterpreterResolvedJavaType getResolvedType() {
78+
if (resolvedType == null) {
79+
Class<?> cls = CremaSupport.singleton().resolveOrThrow(UnresolvedJavaType.create(getSymbolicType().toString()), getDeclaringClass());
80+
resolvedType = (InterpreterResolvedJavaType) DynamicHub.fromClass(cls).getInterpreterType();
81+
}
82+
return resolvedType;
83+
}
84+
85+
@Override
86+
public boolean isTrustedFinal() {
87+
return isFinal() && (isStatic() || Record.class.isAssignableFrom(getDeclaringClass().getJavaClass()) /*- GR-69549: || getDeclaringClass().isHidden() */);
88+
}
89+
90+
@Override
91+
public byte[] getRawAnnotations() {
92+
/* (GR-69096) resolvedJavaField.getRawAnnotations() */
93+
return new byte[0];
94+
}
95+
96+
@Override
97+
public byte[] getRawTypeAnnotations() {
98+
/* (GR-69096) resolvedJavaMethod.getRawTypeAnnotations() */
99+
return new byte[0];
100+
}
101+
102+
@Override
103+
public String getGenericSignature() {
104+
/* (GR-69096) resolvedJavaMethod.getGenericSignature() */
105+
return getSymbolicType().toString();
106+
}
107+
}

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaResolvedObjectType.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
*/
2525
package com.oracle.svm.interpreter.metadata;
2626

27-
import com.oracle.svm.core.hub.crema.CremaResolvedJavaField;
27+
import java.util.ArrayList;
28+
2829
import com.oracle.svm.core.hub.crema.CremaResolvedJavaMethod;
2930
import com.oracle.svm.core.hub.crema.CremaResolvedJavaRecordComponent;
3031
import com.oracle.svm.core.hub.crema.CremaResolvedJavaType;
@@ -35,8 +36,6 @@
3536
import jdk.vm.ci.meta.JavaType;
3637
import jdk.vm.ci.meta.ResolvedJavaType;
3738

38-
import java.util.ArrayList;
39-
4039
public final class CremaResolvedObjectType extends InterpreterResolvedObjectType implements CremaResolvedJavaType {
4140

4241
public CremaResolvedObjectType(Symbol<Type> type, int modifiers, InterpreterResolvedJavaType componentType, InterpreterResolvedObjectType superclass, InterpreterResolvedObjectType[] interfaces,
@@ -45,9 +44,8 @@ public CremaResolvedObjectType(Symbol<Type> type, int modifiers, InterpreterReso
4544
}
4645

4746
@Override
48-
public CremaResolvedJavaField[] getDeclaredFields() {
49-
// (GR-69098)
50-
throw VMError.unimplemented("getDeclaredFields");
47+
public CremaResolvedJavaFieldImpl[] getDeclaredFields() {
48+
return (CremaResolvedJavaFieldImpl[]) declaredFields;
5149
}
5250

5351
@Override

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaTypeAccess.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import com.oracle.svm.core.hub.registry.SymbolsSupport;
2828
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
2929
import com.oracle.svm.espresso.classfile.descriptors.Type;
30+
import com.oracle.svm.espresso.classfile.descriptors.TypeSymbols;
3031
import com.oracle.svm.espresso.shared.meta.TypeAccess;
3132

33+
import jdk.vm.ci.meta.JavaKind;
34+
3235
public interface CremaTypeAccess extends WithModifiers, TypeAccess<InterpreterResolvedJavaType, InterpreterResolvedJavaMethod, InterpreterResolvedJavaField> {
3336
static Symbol<Type> jvmciNameToType(String name) {
3437
// hidden classes and SVM stable proxy name contain a `.`
@@ -39,4 +42,11 @@ static Symbol<Type> jvmciNameToType(String name) {
3942
}
4043
return type;
4144
}
45+
46+
static JavaKind symbolToJvmciKind(Symbol<Type> type) {
47+
if (TypeSymbols.isPrimitive(type)) {
48+
return JavaKind.fromPrimitiveOrVoidTypeChar((char) type.byteAt(0));
49+
}
50+
return JavaKind.Object;
51+
}
4252
}

0 commit comments

Comments
 (0)