34
34
35
35
import org .graalvm .nativeimage .CurrentIsolate ;
36
36
import org .graalvm .nativeimage .IsolateThread ;
37
+ import org .graalvm .nativeimage .StackValue ;
37
38
import org .graalvm .nativeimage .c .struct .SizeOf ;
38
39
import org .graalvm .nativeimage .c .type .WordPointer ;
39
40
import org .graalvm .word .Pointer ;
@@ -158,10 +159,52 @@ public static void initialize(IsolateThread thread) {
158
159
resetStatistics (thread );
159
160
}
160
161
162
+ @ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/gc/shared/memAllocator.cpp#L257-L329" )
163
+ @ Uninterruptible (reason = "Holds uninitialized memory." )
164
+ static Pointer allocateRawMemoryInTlabSlow (UnsignedWord size ) {
165
+ ThreadLocalAllocation .Descriptor tlab = getTlab ();
166
+
167
+ /*
168
+ * Retain tlab and allocate object as an heap allocation if the amount free in the tlab is
169
+ * too large to discard.
170
+ */
171
+ if (shouldRetainTlab (tlab )) {
172
+ recordSlowAllocation ();
173
+ return Word .nullPointer ();
174
+ }
175
+
176
+ /* Discard tlab and allocate a new one. */
177
+ recordRefillWaste ();
178
+ retireTlab (CurrentIsolate .getCurrentThread (), false );
179
+
180
+ /* To minimize fragmentation, the last tlab may be smaller than the rest. */
181
+ UnsignedWord newTlabSize = computeSizeOfNewTlab (size );
182
+ if (newTlabSize .equal (0 )) {
183
+ return Word .nullPointer ();
184
+ }
185
+
186
+ /*
187
+ * Allocate a new TLAB requesting newTlabSize. Any size between minimal and newTlabSize is
188
+ * accepted.
189
+ */
190
+ UnsignedWord computedMinSize = computeMinSizeOfNewTlab (size );
191
+
192
+ WordPointer allocatedTlabSize = StackValue .get (WordPointer .class );
193
+ Pointer memory = YoungGeneration .getHeapAllocation ().allocateNewTlab (computedMinSize , newTlabSize , allocatedTlabSize );
194
+ if (memory .isNull ()) {
195
+ assert Word .unsigned (0 ).equal (allocatedTlabSize .read ()) : "Allocation failed, but actual size was updated." ;
196
+ return Word .nullPointer ();
197
+ }
198
+ assert Word .unsigned (0 ).notEqual (allocatedTlabSize .read ()) : "Allocation succeeded but actual size not updated." ;
199
+
200
+ fillTlab (memory , memory .add (size ), allocatedTlabSize );
201
+ return memory ;
202
+ }
203
+
161
204
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/runtime/thread.cpp#L168-L174" )
162
205
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-23-ga/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L183-L195" )
163
206
@ Uninterruptible (reason = "Accesses TLAB" )
164
- static void fillTlab (Pointer start , Pointer top , WordPointer newSize ) {
207
+ private static void fillTlab (Pointer start , Pointer top , WordPointer newSize ) {
165
208
/* Fill the TLAB. */
166
209
numberOfRefills .set (numberOfRefills .get () + 1 );
167
210
@@ -178,15 +221,15 @@ static void fillTlab(Pointer start, Pointer top, WordPointer newSize) {
178
221
179
222
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L143-L145" )
180
223
@ Uninterruptible (reason = "Accesses TLAB" )
181
- static void recordRefillWaste () {
224
+ private static void recordRefillWaste () {
182
225
long availableTlabMemory = availableTlabMemory (getTlab ()).rawValue ();
183
226
refillWaste .set (refillWaste .get () + UninterruptibleUtils .NumUtil .safeToInt (availableTlabMemory ));
184
227
}
185
228
186
229
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/runtime/thread.cpp#L157-L166" )
187
230
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L131-L141" )
188
231
@ Uninterruptible (reason = "Accesses TLAB" )
189
- static void retireTlab (IsolateThread thread , boolean calculateStats ) {
232
+ private static void retireTlab (IsolateThread thread , boolean calculateStats ) {
190
233
/* Sampling and serviceability support. */
191
234
ThreadLocalAllocation .Descriptor tlab = getTlab (thread );
192
235
if (tlab .getAllocationEnd (TLAB_END_IDENTITY ).isNonNull ()) {
@@ -284,7 +327,7 @@ private static void retireTlabToEden(IsolateThread thread) {
284
327
}
285
328
286
329
@ Uninterruptible (reason = "Accesses TLAB" )
287
- static UnsignedWord availableTlabMemory (Descriptor tlab ) {
330
+ private static UnsignedWord availableTlabMemory (Descriptor tlab ) {
288
331
Pointer top = tlab .getAllocationTop (TLAB_TOP_IDENTITY );
289
332
Pointer end = tlab .getAllocationEnd (TLAB_END_IDENTITY );
290
333
assert top .belowOrEqual (end );
@@ -322,7 +365,6 @@ private static void insertFiller(ThreadLocalAllocation.Descriptor tlab) {
322
365
if (top .belowThan (hardEnd )) {
323
366
FillerObjectUtil .writeFillerObjectAt (top , size );
324
367
}
325
-
326
368
}
327
369
328
370
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-23-ga/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L175-L181" )
@@ -384,7 +426,7 @@ private static UnsignedWord initialRefillWasteLimit() {
384
426
385
427
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+8/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp#L54-L71" )
386
428
@ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
387
- static UnsignedWord computeSizeOfNewTlab (UnsignedWord allocationSize ) {
429
+ private static UnsignedWord computeSizeOfNewTlab (UnsignedWord allocationSize ) {
388
430
assert UnsignedUtils .isAMultiple (allocationSize , Word .unsigned (ConfigurationValues .getObjectLayout ().getAlignment ()));
389
431
390
432
/*
@@ -403,7 +445,7 @@ static UnsignedWord computeSizeOfNewTlab(UnsignedWord allocationSize) {
403
445
404
446
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-23-ga/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp#L73-L77" )
405
447
@ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
406
- static UnsignedWord computeMinSizeOfNewTlab (UnsignedWord allocationSize ) {
448
+ private static UnsignedWord computeMinSizeOfNewTlab (UnsignedWord allocationSize ) {
407
449
UnsignedWord alignedSize = Word .unsigned (ConfigurationValues .getObjectLayout ().alignUp (allocationSize .rawValue ()));
408
450
UnsignedWord sizeWithReserve = alignedSize .add (getFillerObjectSize ());
409
451
long minTlabSize = TlabOptionCache .singleton ().getMinTlabSize ();
@@ -412,13 +454,13 @@ static UnsignedWord computeMinSizeOfNewTlab(UnsignedWord allocationSize) {
412
454
}
413
455
414
456
@ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
415
- static boolean shouldRetainTlab (Descriptor tlab ) {
457
+ private static boolean shouldRetainTlab (Descriptor tlab ) {
416
458
return availableTlabMemory (tlab ).aboveThan (refillWasteLimit .get ());
417
459
}
418
460
419
461
@ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+11/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp#L79-L94" )
420
462
@ Uninterruptible (reason = CALLED_FROM_UNINTERRUPTIBLE_CODE , mayBeInlined = true )
421
- static void recordSlowAllocation () {
463
+ private static void recordSlowAllocation () {
422
464
/*
423
465
* Raise size required to bypass TLAB next time. Else there's a risk that a thread that
424
466
* repeatedly allocates objects of one size will get stuck on this slow path.
@@ -469,7 +511,6 @@ static void logTlabChunks(Log log, IsolateThread thread, String shortSpaceName)
469
511
ThreadLocalAllocation .Descriptor tlab = getTlabUnsafe (thread );
470
512
471
513
// Aligned chunks are handled in HeapAllocation.
472
-
473
514
UnalignedHeapChunk .UnalignedHeader uChunk = tlab .getUnalignedChunk ();
474
515
HeapChunkLogging .logChunks (log , uChunk , shortSpaceName , false );
475
516
}
0 commit comments