Skip to content

Commit 184ad00

Browse files
committed
[GR-49708] Separate DynamicHub from HybridLayout.
PullRequest: graal/16090
2 parents 013798b + c26f970 commit 184ad00

File tree

16 files changed

+423
-187
lines changed

16 files changed

+423
-187
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import com.oracle.svm.core.image.ImageHeapPartition;
4040
import com.oracle.svm.core.meta.SubstrateObjectConstant;
4141

42+
import jdk.graal.compiler.debug.Assertions;
43+
4244
/**
4345
* The image heap comes in partitions. Each partition holds objects with different properties
4446
* (read-only/writable, primitives/objects).
@@ -143,7 +145,7 @@ private NavigableMap<Long, Queue<ImageHeapObject>> createSortedObjectsMap() {
143145
for (ImageHeapObject obj : sorted) {
144146
long objSize = obj.getSize();
145147
if (objSize != currentObjectsSize) {
146-
assert objSize > currentObjectsSize && objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize();
148+
assert objSize > currentObjectsSize && objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize() : Assertions.errorMessage(obj, objSize);
147149
currentObjectsSize = objSize;
148150
currentQueue = new ArrayDeque<>();
149151
map.put(currentObjectsSize, currentQueue);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
* object needs the field, the object is resized during garbage collection to accommodate the
5555
* field.</li>
5656
* </ol>
57+
*
58+
* See this classes instantiation sites (such as {@code HostedConfiguration#createObjectLayout}) for
59+
* more details on the exact object layout for a given configuration.
5760
*/
5861
public final class ObjectLayout {
5962

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@
132132
import sun.reflect.generics.factory.GenericsFactory;
133133
import sun.reflect.generics.repository.ClassRepository;
134134

135-
@Hybrid
135+
/**
136+
* Instantiations of this class have a special layout. See {@code DynamicHubLayout} for a
137+
* description of how the object is arranged.
138+
*/
136139
@Substitute
137140
@TargetClass(java.lang.Class.class)
138141
@SuppressWarnings({"static-method", "serial"})
@@ -344,10 +347,10 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ
344347
* match the assignee's type.
345348
*/
346349
@UnknownObjectField(availability = AfterHostedUniverse.class)//
347-
@Hybrid.TypeIDSlots private short[] typeCheckSlots;
350+
private short[] typeCheckSlots;
348351

349352
@UnknownObjectField(availability = AfterHostedUniverse.class)//
350-
@Hybrid.Array private CFunctionPointer[] vtable;
353+
private CFunctionPointer[] vtable;
351354

352355
/** Field used for module information access at run-time. */
353356
private Module module;

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

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,28 @@
2929
import java.lang.annotation.RetentionPolicy;
3030
import java.lang.annotation.Target;
3131

32+
import com.oracle.svm.core.config.ObjectLayout;
33+
import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport;
34+
3235
/**
3336
* Defines that the annotated class should have a Hybrid layout. Hybrid layouts are hybrids between
3437
* instance layouts and array layouts. The contents of a specified member array and (optional)
3538
* member type id slots are directly placed within the class layout. This saves one indirection when
3639
* accessing the array or type id slots.
37-
*
40+
*
41+
* <p>
42+
* The location of the identity hashcode is configuration-dependent and will follow the same
43+
* placement convention as an array. The See {@link ObjectLayout} for more information on where the
44+
* identity hash can be placed. @Hybrid objects are treated the same way as instance classes for
45+
* determining whether (and where) they have a monitor slot; See {@link MultiThreadedMonitorSupport}
46+
* for more information on monitor slot placement.
47+
*
3848
* <pre>
3949
* +--------------------------------------------------+
4050
* | object header (same header as for arrays) |
4151
* +--------------------------------------------------+
4252
* | array length |
4353
* +--------------------------------------------------+
44-
* | type id slots (i.e., optional primitive data) |
45-
* | ... |
46-
* +--------------------------------------------------+
4754
* | instance fields (i.e., primitive or object data) |
4855
* | ... |
4956
* +--------------------------------------------------+
@@ -64,32 +71,7 @@
6471
public @interface Hybrid {
6572

6673
/**
67-
* The component type of the array part of the hybrid class. Must be specified if no field
68-
* annotated with @{@link Hybrid.Array} is declared, otherwise that field's type determines the
69-
* type of the array part.
74+
* The component type of the array part of the hybrid class.
7075
*/
71-
Class<?> componentType() default void.class;
72-
73-
/**
74-
* If {@code true}, allow the data in the hybrid fields to be duplicated between the hybrid
75-
* object and a separate object for the array. For image heap objects, a duplication can occur
76-
* if inlining and constant folding result in the internal reference to a hybrid field being
77-
* folded to a constant value, which must be written into the image heap separately from the
78-
* hybrid object.
79-
*
80-
* If {@code false}, a duplication of the hybrid fields must never happen.
81-
*/
82-
boolean canHybridFieldsBeDuplicated() default false;
83-
84-
/** Designates at most one field that refers to the array part of the hybrid object. */
85-
@Retention(RetentionPolicy.RUNTIME)
86-
@Target(ElementType.FIELD)
87-
@interface Array {
88-
}
89-
90-
/** Designates at most one field that refers to the type ID slots of the hybrid object. */
91-
@Retention(RetentionPolicy.RUNTIME)
92-
@Target(ElementType.FIELD)
93-
@interface TypeIDSlots {
94-
}
76+
Class<?> componentType();
9577
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ public static int forHybrid(ResolvedJavaType type, boolean objectElements, int a
139139
return forArrayLike(type, true, objectElements, arrayBaseOffset, arrayIndexShift);
140140
}
141141

142+
@Platforms(Platform.HOSTED_ONLY.class)
143+
public static int forDynamicHub(ResolvedJavaType type, int vtableOffset, int vtableIndexShift) {
144+
return forArrayLike(type, true, false, vtableOffset, vtableIndexShift);
145+
}
146+
142147
@Platforms(Platform.HOSTED_ONLY.class)
143148
private static int forArrayLike(ResolvedJavaType type, boolean isHybrid, boolean objectElements, int arrayBaseOffset, int arrayIndexShift) {
144149
assert isHybrid != type.isArray();

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

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,13 @@
5151
import com.oracle.svm.core.config.ObjectLayout.IdentityHashMode;
5252
import com.oracle.svm.core.graal.code.SubstrateMetaAccessExtensionProvider;
5353
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
54+
import com.oracle.svm.core.hub.DynamicHub;
5455
import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport;
5556
import com.oracle.svm.hosted.analysis.Inflation;
5657
import com.oracle.svm.hosted.analysis.flow.SVMMethodTypeFlowBuilder;
5758
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
5859
import com.oracle.svm.hosted.code.CompileQueue;
60+
import com.oracle.svm.hosted.config.DynamicHubLayout;
5961
import com.oracle.svm.hosted.config.HybridLayout;
6062
import com.oracle.svm.hosted.config.HybridLayoutSupport;
6163
import com.oracle.svm.hosted.image.LIRNativeImageCodeCache;
@@ -66,8 +68,10 @@
6668
import com.oracle.svm.hosted.meta.HostedField;
6769
import com.oracle.svm.hosted.meta.HostedInstanceClass;
6870
import com.oracle.svm.hosted.meta.HostedMetaAccess;
71+
import com.oracle.svm.hosted.meta.HostedType;
6972
import com.oracle.svm.hosted.meta.HostedUniverse;
7073
import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
74+
import com.oracle.svm.util.ReflectionUtil;
7175

7276
import jdk.graal.compiler.api.replacements.SnippetReflectionProvider;
7377
import jdk.graal.compiler.core.common.CompressEncoding;
@@ -162,6 +166,37 @@ public static ObjectLayout createObjectLayout(JavaKind referenceKind, IdentityHa
162166
return new ObjectLayout(target, referenceSize, objectAlignment, hubOffset, firstFieldOffset, arrayLengthOffset, arrayBaseOffset, headerIdentityHashOffset, identityHashMode);
163167
}
164168

169+
public static void initializeDynamicHubLayout(HostedMetaAccess hMeta) {
170+
ImageSingletons.add(DynamicHubLayout.class, createDynamicHubLayout(hMeta));
171+
}
172+
173+
private static DynamicHubLayout createDynamicHubLayout(HostedMetaAccess hMetaAccess) {
174+
var dynamicHubType = hMetaAccess.lookupJavaType(Class.class);
175+
var typeIDSlotsField = hMetaAccess.lookupJavaField(ReflectionUtil.lookupField(DynamicHub.class, "typeCheckSlots"));
176+
var vtableField = hMetaAccess.lookupJavaField(ReflectionUtil.lookupField(DynamicHub.class, "vtable"));
177+
178+
ObjectLayout layout = ConfigurationValues.getObjectLayout();
179+
int typeIDSlotsOffset = layout.getArrayLengthOffset() + layout.sizeInBytes(JavaKind.Int);
180+
int typeIDSlotsSize = layout.sizeInBytes(typeIDSlotsField.getType().getComponentType().getStorageKind());
181+
182+
JavaKind vTableSlotStorageKind = vtableField.getType().getComponentType().getStorageKind();
183+
int vTableSlotSize = layout.sizeInBytes(vTableSlotStorageKind);
184+
185+
return new DynamicHubLayout(layout, dynamicHubType, typeIDSlotsField, typeIDSlotsOffset, typeIDSlotsSize, vtableField, vTableSlotStorageKind, vTableSlotSize);
186+
}
187+
188+
public static boolean isArrayLikeLayout(HostedType clazz) {
189+
return HybridLayout.isHybrid(clazz) || DynamicHubLayout.singleton().isDynamicHub(clazz);
190+
}
191+
192+
/**
193+
* The hybrid array field and the type fields of the dynamic hub are directly inlined to the
194+
* object to remove a level of indirection.
195+
*/
196+
public static boolean isInlinedField(HostedField field) {
197+
return HybridLayout.isHybridField(field) || DynamicHubLayout.singleton().isInlinedField(field);
198+
}
199+
165200
public SVMHost createHostVM(OptionValues options, ImageClassLoader loader, ClassInitializationSupport classInitializationSupport, AnnotationSubstitutionProcessor annotationSubstitutions) {
166201
return new SVMHost(options, loader, classInitializationSupport, annotationSubstitutions);
167202
}
@@ -191,16 +226,22 @@ public MetaAccessExtensionProvider createCompilationMetaAccessExtensionProvider(
191226
public void findAllFieldsForLayout(HostedUniverse universe, @SuppressWarnings("unused") HostedMetaAccess metaAccess,
192227
@SuppressWarnings("unused") Map<AnalysisField, HostedField> universeFields,
193228
ArrayList<HostedField> rawFields, ArrayList<HostedField> allFields, HostedInstanceClass clazz) {
229+
DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton();
194230
for (ResolvedJavaField javaField : clazz.getWrapped().getInstanceFields(false)) {
195231
AnalysisField aField = (AnalysisField) javaField;
196232
HostedField hField = universe.lookup(aField);
197233

198234
/* Because of @Alias fields, the field lookup might not be declared in our class. */
199235
if (hField.getDeclaringClass().equals(clazz)) {
200-
if (HybridLayout.isHybridField(hField)) {
236+
if (dynamicHubLayout.isInlinedField(hField)) {
237+
/*
238+
* The typeid slots and the vtable of the dynamic hub are not materialized, so
239+
* they need no field offset.
240+
*/
241+
allFields.add(hField);
242+
} else if (HybridLayout.isHybridField(hField)) {
201243
/*
202-
* The array or bitset field of a hybrid is not materialized, so it needs no
203-
* field offset.
244+
* The array field of a hybrid is not materialized, so it needs no field offset.
204245
*/
205246
allFields.add(hField);
206247
} else if (hField.isAccessed()) {
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright (c) 2023, 2023, 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.hosted.config;
26+
27+
import org.graalvm.nativeimage.ImageSingletons;
28+
29+
import com.oracle.svm.core.config.ObjectLayout;
30+
import com.oracle.svm.core.hub.DynamicHub;
31+
import com.oracle.svm.core.hub.HubType;
32+
import com.oracle.svm.core.hub.Hybrid;
33+
import com.oracle.svm.core.hub.LayoutEncoding;
34+
import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport;
35+
import com.oracle.svm.hosted.meta.HostedField;
36+
import com.oracle.svm.hosted.meta.HostedInstanceClass;
37+
import com.oracle.svm.hosted.meta.HostedType;
38+
39+
import jdk.graal.compiler.core.common.NumUtil;
40+
import jdk.vm.ci.meta.JavaKind;
41+
42+
/**
43+
* Provides sizes and offsets of the {@link DynamicHub} class. Like {@link Hybrid} layouts,
44+
* DynamicHubs contain both instance fields and a variable length array to hold the virtual dispatch
45+
* table. In addition, to save a level of indirection, there is a fixed-length typeid slot directly
46+
* placed within the dynamic hub.
47+
*
48+
* <p>
49+
* The location of the identity hashcode is configuration-dependent and will follow the same
50+
* placement convention as an array. See {@link ObjectLayout} for more information on where the
51+
* identity hash can be placed. DynamicHubs never have a monitor slot; See
52+
* {@link MultiThreadedMonitorSupport} for more information.
53+
*
54+
* <pre>
55+
* +--------------------------------------------------+
56+
* | object header (same header as for arrays) |
57+
* +--------------------------------------------------+
58+
* | vtable length |
59+
* +--------------------------------------------------+
60+
* | type id slots (i.e., primitive data) |
61+
* | ... |
62+
* +--------------------------------------------------+
63+
* | instance fields (i.e., primitive or object data) |
64+
* | ... |
65+
* +--------------------------------------------------+
66+
* | vtable dispatch addresses (i.e., primitive data) |
67+
* | ... |
68+
* +--------------------------------------------------+
69+
* </pre>
70+
*
71+
* <p>
72+
* Like {@link Hybrid}, DynamicHub objects have an instance {@link HubType}, but a
73+
* {@link LayoutEncoding} like an array. See the javadoc for {@link Hybrid} more details its
74+
* implications.
75+
*/
76+
public class DynamicHubLayout {
77+
78+
private final ObjectLayout layout;
79+
private final HostedInstanceClass dynamicHubType;
80+
public final HostedField typeIDSlotsField;
81+
public final int typeIDSlotsOffset;
82+
public final int typeIDSlotsSize;
83+
public final HostedField vTableField;
84+
public final int vTableSlotSize;
85+
public final JavaKind vTableSlotStorageKind;
86+
87+
/*
88+
* This is calculated lazily, as it requires the dynamicHub's instance fields to be finalized
89+
* before being calculated.
90+
*/
91+
private int vTableOffset;
92+
93+
public DynamicHubLayout(ObjectLayout layout, HostedType dynamicHubType, HostedField typeIDSlotsField, int typeIDSlotsOffset, int typeIDSlotsSize, HostedField vTableField,
94+
JavaKind vTableSlotStorageKind, int vTableSlotSize) {
95+
this.layout = layout;
96+
this.dynamicHubType = (HostedInstanceClass) dynamicHubType;
97+
this.typeIDSlotsField = typeIDSlotsField;
98+
this.typeIDSlotsOffset = typeIDSlotsOffset;
99+
this.typeIDSlotsSize = typeIDSlotsSize;
100+
this.vTableField = vTableField;
101+
this.vTableSlotStorageKind = vTableSlotStorageKind;
102+
this.vTableSlotSize = vTableSlotSize;
103+
}
104+
105+
public static DynamicHubLayout singleton() {
106+
return ImageSingletons.lookup(DynamicHubLayout.class);
107+
}
108+
109+
public JavaKind getVTableSlotStorageKind() {
110+
return vTableSlotStorageKind;
111+
}
112+
113+
public boolean isDynamicHub(HostedType type) {
114+
return type.equals(dynamicHubType);
115+
}
116+
117+
public boolean isInlinedField(HostedField field) {
118+
return field.equals(typeIDSlotsField) || field.equals(vTableField);
119+
}
120+
121+
public int getVTableSlotOffset(int index) {
122+
return vTableOffset() + index * vTableSlotSize;
123+
}
124+
125+
public int getTypeIDSlotsOffset(int index) {
126+
return typeIDSlotsOffset + index * typeIDSlotsSize;
127+
}
128+
129+
public int getVTableLengthOffset() {
130+
return layout.getArrayLengthOffset();
131+
}
132+
133+
public int vTableOffset() {
134+
if (vTableOffset == 0) {
135+
vTableOffset = NumUtil.roundUp(dynamicHubType.getAfterFieldsOffset(), vTableSlotSize);
136+
}
137+
return vTableOffset;
138+
}
139+
140+
public long getTotalSize(int vtableLength) {
141+
return layout.computeArrayTotalSize(getVTableSlotOffset(vtableLength), true);
142+
}
143+
144+
public long getIdentityHashOffset(int vTableLength) {
145+
return layout.getArrayIdentityHashOffset(getVTableSlotOffset(vTableLength));
146+
}
147+
}

0 commit comments

Comments
 (0)