Skip to content

Commit 6f2e88b

Browse files
committed
Fixes and improvements.
1 parent 5f7626d commit 6f2e88b

File tree

14 files changed

+135
-72
lines changed

14 files changed

+135
-72
lines changed

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -224,15 +224,15 @@ private static Object slowPathNewInstanceWithoutAllocating(DynamicHub hub) {
224224

225225
@SubstrateForeignCallTarget(stubCallingConvention = false)
226226
private static Object slowPathNewArray(Word objectHeader, int length, int fillStartOffset) {
227-
return slowPathNewArrayImpl(objectHeader, length, fillStartOffset, null);
227+
return slowPathNewArrayOrPodImpl(objectHeader, length, fillStartOffset, null);
228228
}
229229

230230
@SubstrateForeignCallTarget(stubCallingConvention = false)
231231
private static Object slowPathNewPodInstance(Word objectHeader, int arrayLength, int fillStartOffset, byte[] referenceMap) {
232-
return slowPathNewArrayImpl(objectHeader, arrayLength, fillStartOffset, referenceMap);
232+
return slowPathNewArrayOrPodImpl(objectHeader, arrayLength, fillStartOffset, referenceMap);
233233
}
234234

235-
private static Object slowPathNewArrayImpl(Word objectHeader, int length, int fillStartOffset, byte[] podReferenceMap) {
235+
private static Object slowPathNewArrayOrPodImpl(Word objectHeader, int length, int fillStartOffset, byte[] podReferenceMap) {
236236
/*
237237
* Avoid stack overflow errors while producing memory chunks, because that could leave the
238238
* heap in an inconsistent state.
@@ -256,7 +256,7 @@ private static Object slowPathNewArrayImpl(Word objectHeader, int length, int fi
256256
throw OutOfMemoryUtil.reportOutOfMemoryError(outOfMemoryError);
257257
}
258258

259-
Object result = slowPathNewArrayWithoutAllocating(hub, length, size, fillStartOffset, podReferenceMap);
259+
Object result = slowPathNewArrayOrPodWithoutAllocating(hub, length, size, fillStartOffset, podReferenceMap);
260260
runSlowPathHooks();
261261
return result;
262262
} finally {
@@ -265,26 +265,26 @@ private static Object slowPathNewArrayImpl(Word objectHeader, int length, int fi
265265
}
266266

267267
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate in the implementation of allocation.")
268-
private static Object slowPathNewArrayWithoutAllocating(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, byte[] podReferenceMap) {
268+
private static Object slowPathNewArrayOrPodWithoutAllocating(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, byte[] podReferenceMap) {
269269
DeoptTester.disableDeoptTesting();
270270
try {
271-
HeapImpl.exitIfAllocationDisallowed("ThreadLocalAllocation.slowPathNewArrayWithoutAllocating", DynamicHub.toClass(hub).getName());
271+
HeapImpl.exitIfAllocationDisallowed("ThreadLocalAllocation.slowPathNewArrayOrPodWithoutAllocating", DynamicHub.toClass(hub).getName());
272272
GCImpl.getGCImpl().maybeCollectOnAllocation();
273273

274274
if (size.aboveOrEqual(HeapParameters.getLargeArrayThreshold())) {
275275
/* Large arrays go into their own unaligned chunk. */
276276
boolean needsZeroing = !HeapChunkProvider.areUnalignedChunksZeroed();
277277
UnalignedHeapChunk.UnalignedHeader newTlabChunk = HeapImpl.getChunkProvider().produceUnalignedChunk(size);
278-
return allocateLargeArrayInNewTlab(hub, length, size, fillStartOffset, newTlabChunk, needsZeroing, podReferenceMap);
278+
return allocateLargeArrayOrPodInNewTlab(hub, length, size, fillStartOffset, newTlabChunk, needsZeroing, podReferenceMap);
279279
}
280280
/* Small arrays go into the regular aligned chunk. */
281281

282282
// We might have allocated in the caller and acquired a TLAB with enough space already
283283
// (but we need to check in an uninterruptible method to be safe)
284-
Object array = allocateSmallArrayInCurrentTlab(hub, length, size, fillStartOffset, podReferenceMap);
284+
Object array = allocateSmallArrayOrPodInCurrentTlab(hub, length, size, fillStartOffset, podReferenceMap);
285285
if (array == null) { // We need a new chunk.
286286
AlignedHeader newTlabChunk = HeapImpl.getChunkProvider().produceAlignedChunk();
287-
array = allocateSmallArrayInNewTlab(hub, length, size, fillStartOffset, newTlabChunk, podReferenceMap);
287+
array = allocateSmallArrayOrPodInNewTlab(hub, length, size, fillStartOffset, newTlabChunk, podReferenceMap);
288288
}
289289
return array;
290290
} finally {
@@ -300,7 +300,7 @@ private static Object allocateInstanceInNewTlab(DynamicHub hub, AlignedHeader ne
300300
}
301301

302302
@Uninterruptible(reason = "Holds uninitialized memory.")
303-
private static Object allocateSmallArrayInCurrentTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, byte[] podReferenceMap) {
303+
private static Object allocateSmallArrayOrPodInCurrentTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, byte[] podReferenceMap) {
304304
if (size.aboveThan(availableTlabMemory(getTlab()))) {
305305
return null;
306306
}
@@ -309,13 +309,15 @@ private static Object allocateSmallArrayInCurrentTlab(DynamicHub hub, int length
309309
}
310310

311311
@Uninterruptible(reason = "Holds uninitialized memory.")
312-
private static Object allocateSmallArrayInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, AlignedHeader newTlabChunk, byte[] podReferenceMap) {
312+
private static Object allocateSmallArrayOrPodInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, AlignedHeader newTlabChunk, byte[] podReferenceMap) {
313313
Pointer memory = allocateRawMemoryInNewTlab(size, newTlabChunk);
314314
return formatArrayOrPod(memory, hub, length, false, FillContent.WITH_ZEROES, fillStartOffset, podReferenceMap);
315315
}
316316

317317
@Uninterruptible(reason = "Holds uninitialized memory, modifies TLAB")
318-
private static Object allocateLargeArrayInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, UnalignedHeader newTlabChunk, boolean needsZeroing, byte[] podReferenceMap) {
318+
private static Object allocateLargeArrayOrPodInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset,
319+
UnalignedHeader newTlabChunk, boolean needsZeroing, byte[] podReferenceMap) {
320+
319321
ThreadLocalAllocation.Descriptor tlab = getTlab();
320322

321323
HeapChunk.setNext(newTlabChunk, tlab.getUnalignedChunk());
@@ -344,7 +346,7 @@ private static Object allocateLargeArrayInNewTlab(DynamicHub hub, int length, Un
344346
private static Object formatArrayOrPod(Pointer memory, DynamicHub hub, int length, boolean unaligned, FillContent fillContent, int fillStartOffset, byte[] podReferenceMap) {
345347
Class<?> clazz = DynamicHub.toClass(hub);
346348
if (podReferenceMap != null) {
347-
return FormatPodNode.formatPod(memory, clazz, length, podReferenceMap, false, unaligned, fillStartOffset, true);
349+
return FormatPodNode.formatPod(memory, clazz, length, podReferenceMap, false, unaligned, fillContent, fillStartOffset, true);
348350
}
349351
return FormatArrayNode.formatArray(memory, clazz, length, false, unaligned, fillContent, fillStartOffset, true);
350352
}

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public Object allocatePod(@NonNullParameter DynamicHub hub, int arrayLength, byt
135135
if (useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
136136
writeTlabTop(thread, newTop);
137137
emitPrefetchAllocate(newTop, true);
138-
instance = formatPod(top, hub, arrayLength, referenceMap, false, false, afterArrayLengthOffset(),
138+
instance = formatPod(top, hub, arrayLength, referenceMap, false, false, FillContent.WITH_ZEROES, afterArrayLengthOffset(),
139139
emitMemoryBarrier, maybeUnroll, supportsBulkZeroing, supportsOptimizedFilling, profilingData.snippetCounters);
140140
} else {
141141
profilingData.snippetCounters.stub.inc();
@@ -146,23 +146,24 @@ public Object allocatePod(@NonNullParameter DynamicHub hub, int arrayLength, byt
146146
}
147147

148148
@Snippet
149-
public Object formatPodSnippet(Word memory, DynamicHub hub, int arrayLength, byte[] referenceMap, boolean rememberedSet, boolean unaligned, int fillStartOffset, boolean emitMemoryBarrier,
150-
@ConstantParameter boolean supportsBulkZeroing, @ConstantParameter boolean supportsOptimizedFilling, @ConstantParameter AllocationSnippetCounters snippetCounters) {
149+
public Object formatPodSnippet(Word memory, DynamicHub hub, int arrayLength, byte[] referenceMap, boolean rememberedSet, boolean unaligned,
150+
FillContent fillContents, int fillStartOffset, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean supportsBulkZeroing,
151+
@ConstantParameter boolean supportsOptimizedFilling, @ConstantParameter AllocationSnippetCounters snippetCounters) {
151152

152153
DynamicHub hubNonNull = (DynamicHub) PiNode.piCastNonNull(hub, SnippetAnchorNode.anchor());
153154
byte[] refMapNonNull = (byte[]) PiNode.piCastNonNull(referenceMap, SnippetAnchorNode.anchor());
154-
return formatPod(memory, hubNonNull, arrayLength, refMapNonNull, rememberedSet, unaligned, fillStartOffset,
155+
return formatPod(memory, hubNonNull, arrayLength, refMapNonNull, rememberedSet, unaligned, fillContents, fillStartOffset,
155156
emitMemoryBarrier, false, supportsBulkZeroing, supportsOptimizedFilling, snippetCounters);
156157
}
157158

158-
private Object formatPod(Word memory, DynamicHub hub, int arrayLength, byte[] referenceMap, boolean rememberedSet, boolean unaligned, int fillStartOffset,
159+
private Object formatPod(Word memory, DynamicHub hub, int arrayLength, byte[] referenceMap, boolean rememberedSet, boolean unaligned, FillContent fillContents, int fillStartOffset,
159160
boolean emitMemoryBarrier, boolean maybeUnroll, boolean supportsBulkZeroing, boolean supportsOptimizedFilling, AllocationSnippetCounters snippetCounters) {
160161

161162
int layoutEncoding = hub.getLayoutEncoding();
162163
UnsignedWord allocationSize = LayoutEncoding.getArraySize(layoutEncoding, arrayLength);
163164

164165
Word objectHeader = encodeAsObjectHeader(hub, rememberedSet, unaligned);
165-
Object instance = formatArray(objectHeader, allocationSize, arrayLength, memory, FillContent.WITH_ZEROES, fillStartOffset,
166+
Object instance = formatArray(objectHeader, allocationSize, arrayLength, memory, fillContents, fillStartOffset,
166167
false, maybeUnroll, supportsBulkZeroing, supportsOptimizedFilling, snippetCounters);
167168

168169
int fromOffset = ConfigurationValues.getObjectLayout().getArrayBaseOffset(JavaKind.Byte);
@@ -341,8 +342,9 @@ public void lower(FormatPodNode node, LoweringTool tool) {
341342
args.add("referenceMap", node.getReferenceMap());
342343
args.add("rememberedSet", node.getRememberedSet());
343344
args.add("unaligned", node.getUnaligned());
345+
args.add("fillContents", node.getFillContents());
344346
args.add("fillStartOffset", node.getFillStartOffset());
345-
args.add("emitMemoryBarrier", node.getEmitMemoryBarrier());
347+
args.addConst("emitMemoryBarrier", node.getEmitMemoryBarrier());
346348
args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing());
347349
args.addConst("supportsOptimizedFilling", tool.getLowerer().supportsOptimizedFilling(graph.getOptions()));
348350
args.addConst("snippetCounters", snippetCounters);

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/nodes/FormatPodNode.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.graalvm.compiler.nodes.FixedWithNextNode;
3434
import org.graalvm.compiler.nodes.ValueNode;
3535
import org.graalvm.compiler.nodes.spi.Lowerable;
36+
import org.graalvm.compiler.replacements.AllocationSnippets;
3637
import org.graalvm.word.Pointer;
3738

3839
@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
@@ -45,18 +46,20 @@ public class FormatPodNode extends FixedWithNextNode implements Lowerable {
4546
@Input protected ValueNode referenceMap;
4647
@Input protected ValueNode rememberedSet;
4748
@Input protected ValueNode unaligned;
49+
@Input protected ValueNode fillContents;
4850
@Input protected ValueNode fillStartOffset;
49-
@Input protected ValueNode emitMemoryBarrier;
51+
private final boolean emitMemoryBarrier;
5052

51-
public FormatPodNode(ValueNode memory, ValueNode hub, ValueNode arrayLength, ValueNode referenceMap,
52-
ValueNode rememberedSet, ValueNode unaligned, ValueNode fillStartOffset, ValueNode emitMemoryBarrier) {
53+
public FormatPodNode(ValueNode memory, ValueNode hub, ValueNode arrayLength, ValueNode referenceMap, ValueNode rememberedSet,
54+
ValueNode unaligned, ValueNode fillContents, ValueNode fillStartOffset, boolean emitMemoryBarrier) {
5355
super(TYPE, StampFactory.objectNonNull());
5456
this.memory = memory;
5557
this.hub = hub;
5658
this.arrayLength = arrayLength;
5759
this.referenceMap = referenceMap;
5860
this.rememberedSet = rememberedSet;
5961
this.unaligned = unaligned;
62+
this.fillContents = fillContents;
6063
this.fillStartOffset = fillStartOffset;
6164
this.emitMemoryBarrier = emitMemoryBarrier;
6265
}
@@ -85,15 +88,19 @@ public ValueNode getUnaligned() {
8588
return unaligned;
8689
}
8790

91+
public ValueNode getFillContents() {
92+
return fillContents;
93+
}
94+
8895
public ValueNode getFillStartOffset() {
8996
return fillStartOffset;
9097
}
9198

92-
public ValueNode getEmitMemoryBarrier() {
99+
public boolean getEmitMemoryBarrier() {
93100
return emitMemoryBarrier;
94101
}
95102

96103
@NodeIntrinsic
97-
public static native Object formatPod(Pointer memory, Class<?> hub, int arrayLength, byte[] referenceMap,
98-
boolean rememberedSet, boolean unaligned, int fillStartOffset, boolean emitMemoryBarrier);
104+
public static native Object formatPod(Pointer memory, Class<?> hub, int arrayLength, byte[] referenceMap, boolean rememberedSet, boolean unaligned,
105+
AllocationSnippets.FillContent fillContents, int fillStartOffset, @ConstantNodeParameter boolean emitMemoryBarrier);
99106
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,18 @@
6262
* important to keep in mind because methods such as {@link Class#isInstance} will return
6363
* {@code true} and {@link Class#isArray()} will return {@code false}, while
6464
* {@link LayoutEncoding#isPureInstance} will return {@code false} and
65-
* {@link LayoutEncoding#isArrayLike} will return {@code true} and for hybrid objects.
65+
* {@link LayoutEncoding#isArrayLike} will return {@code true} for hybrid objects.
6666
*/
6767
@Retention(RetentionPolicy.RUNTIME)
6868
@Target(ElementType.TYPE)
6969
public @interface Hybrid {
7070

7171
/**
72-
* The type of the array part of the hybrid class. Must be specified if no field annotated
73-
* with @{@link Hybrid.Array} is declared, otherwise that field's type determines the type of
74-
* the array part.
72+
* The component type of the array part of the hybrid class. Must be specified if no field
73+
* annotated with @{@link Hybrid.Array} is declared, otherwise that field's type determines the
74+
* type of the array part.
7575
*/
76-
Class<?> arrayType() default Array.class;
76+
Class<?> componentType() default void.class;
7777

7878
/**
7979
* If {@code true}, allow the data in the hybrid fields to be duplicated between the hybrid

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,14 @@ private static Object doClone(Object original) throws CloneNotSupportedException
153153
}
154154

155155
// copy remaining non-object data
156-
if (!isArrayLike) {
157-
int objectSize = UnsignedUtils.safeToInt(LayoutEncoding.getPureInstanceSize(layoutEncoding));
158-
int primitiveDataSize = objectSize - curOffset;
159-
assert primitiveDataSize >= 0;
160-
assert curOffset >= 0;
161-
JavaMemoryUtil.copyForward(original, WordFactory.unsigned(curOffset), result, WordFactory.unsigned(curOffset), WordFactory.unsigned(primitiveDataSize));
162-
curOffset += primitiveDataSize;
163-
assert curOffset == objectSize;
164-
}
156+
int endOffset = isArrayLike ? LayoutEncoding.getArrayBaseOffsetAsInt(layoutEncoding)
157+
: UnsignedUtils.safeToInt(LayoutEncoding.getPureInstanceSize(layoutEncoding));
158+
int primitiveDataSize = endOffset - curOffset;
159+
assert primitiveDataSize >= 0;
160+
assert curOffset >= 0;
161+
JavaMemoryUtil.copyForward(original, WordFactory.unsigned(curOffset), result, WordFactory.unsigned(curOffset), WordFactory.unsigned(primitiveDataSize));
162+
curOffset += primitiveDataSize;
163+
assert curOffset == endOffset;
165164

166165
// reset monitor to uninitialized values
167166
int monitorOffset = hub.getMonitorOffset();
@@ -178,15 +177,15 @@ static boolean canVirtualize(ObjectClone node, VirtualizerTool tool) {
178177
return true;
179178
}
180179
ResolvedJavaType type = node.getConcreteType(alias.stamp(NodeView.DEFAULT));
181-
if (type == null) {
182-
return false;
183-
}
184-
if (!type.isArray() && type instanceof SharedType) {
180+
if (type instanceof SharedType) {
185181
// Hybrids are instances with array-like encoding; cloning virtually is unimplemented.
186182
int encoding = ((SharedType) type).getHub().getLayoutEncoding();
187-
return !LayoutEncoding.isArrayLike(encoding);
183+
return !LayoutEncoding.isHybrid(encoding);
184+
}
185+
if (type != null && type.isArray()) {
186+
return true; // cannot be a hybrid
188187
}
189-
return true;
188+
return false;
190189
}
191190

192191
@NodeIntrinsic(value = ForeignCallNode.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Pod.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,19 @@ public Pod<T> build() {
177177
guaranteeUnbuilt();
178178
built = true;
179179

180+
/*
181+
* We layout the requested fields in the hybrid object's array part in a similar fashion
182+
* as UniverseBuilder does for regular instance fields, putting reference fields at the
183+
* beginning and trying to put narrow fields in alignment gaps between wider fields. The
184+
* entire layout of a pod might look as follows:
185+
*
186+
* [ hub pointer | identity hashcode | array length | superclass instance fields |
187+
* instance fields | monitor | pod fields (ref, short, byte, long) | pod reference map ]
188+
*
189+
* The array length part would provide the combined length of the pod fields and pod
190+
* reference map excluding any alignment padding at their beginning or the object's end.
191+
*/
192+
180193
Collections.sort(fields);
181194

182195
UnsignedWord baseOffset = LayoutEncoding.getArrayBaseOffset(
@@ -346,6 +359,20 @@ void add(int offset, int size) {
346359
bitset.set(index);
347360
}
348361

362+
/**
363+
* Generates a reference map composed of unsigned byte pairs of {@code nrefs} (sequence of n
364+
* references) and {@code gaps} (number of sequential reference-sized primitives). When a
365+
* single lengthy sequence of references or primitives cannot be encoded in an unsigned
366+
* byte, it is encoded in multiple pairs with either gaps or nrefs being 0. The reference
367+
* map covers only the part of the array from the beginning until the last reference. The
368+
* end of the reference map is indicated by a pair with {@code gaps} == 0, unless
369+
* {@code nrefs} is 0xff which could also mean that the pair is part of an ongoing sequence,
370+
* in which case an extra zero pair is added at the end.
371+
*
372+
* We try to place reference fields at the beginning, so the reference map begins with
373+
* {@code nrefs} indicating the number of references right at the start of the array. If
374+
* there are primitive fields at the beginning, this first value will be zero.
375+
*/
349376
byte[] encode() {
350377
if (bitset.isEmpty()) {
351378
return new byte[]{0, 0};
@@ -354,7 +381,7 @@ byte[] encode() {
354381
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
355382
int previous;
356383
int index = 0;
357-
for (;;) { // assume references are placed first
384+
for (;;) {
358385
previous = index;
359386
index = bitset.nextClearBit(previous);
360387
int nrefs = index - previous;

0 commit comments

Comments
 (0)