3333import static com .oracle .svm .core .Isolates .IMAGE_HEAP_WRITABLE_END ;
3434import static com .oracle .svm .core .Isolates .IMAGE_HEAP_WRITABLE_PATCHED_BEGIN ;
3535import static com .oracle .svm .core .Isolates .IMAGE_HEAP_WRITABLE_PATCHED_END ;
36+ import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .CODE_START ;
3637import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_BEGIN ;
3738import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_END ;
3839import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_RELOCATABLE_BEGIN ;
4243import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_WRITEABLE_PATCHED_BEGIN ;
4344import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_WRITEABLE_PATCHED_END ;
4445import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .NEXT_SECTION ;
46+ import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .VARIABLY_SIZED_DATA ;
4547import static com .oracle .svm .core .posix .linux .ProcFSSupport .findMapping ;
4648import static com .oracle .svm .core .util .PointerUtils .roundDown ;
4749import static com .oracle .svm .core .util .UnsignedUtils .isAMultiple ;
4850import static com .oracle .svm .core .util .UnsignedUtils .roundUp ;
4951import static jdk .graal .compiler .word .Word .signed ;
52+ import static jdk .graal .compiler .word .Word .unsigned ;
5053
5154import java .util .concurrent .ThreadLocalRandom ;
5255
7174import com .oracle .svm .core .heap .Heap ;
7275import com .oracle .svm .core .imagelayer .ImageLayerBuildingSupport ;
7376import com .oracle .svm .core .imagelayer .ImageLayerSection ;
77+ import com .oracle .svm .core .jdk .UninterruptibleUtils ;
7478import com .oracle .svm .core .os .AbstractImageHeapProvider ;
7579import com .oracle .svm .core .os .VirtualMemoryProvider ;
7680import com .oracle .svm .core .os .VirtualMemoryProvider .Access ;
8185import com .oracle .svm .core .util .PointerUtils ;
8286import com .oracle .svm .core .util .UnsignedUtils ;
8387import com .oracle .svm .core .util .VMError ;
88+ import com .oracle .svm .hosted .imagelayer .ImageLayerSectionFeature ;
89+ import com .oracle .svm .hosted .imagelayer .LayeredDispatchTableFeature ;
8490
91+ import jdk .graal .compiler .nodes .NamedLocationIdentity ;
8592import jdk .graal .compiler .nodes .PauseNode ;
8693import jdk .graal .compiler .word .Word ;
8794
@@ -122,6 +129,14 @@ public class LinuxImageHeapProvider extends AbstractImageHeapProvider {
122129 */
123130 static final CGlobalData <WordPointer > CACHED_LAYERED_IMAGE_HEAP_ADDRESS_SPACE_SIZE = CGlobalDataFactory .createWord ();
124131
132+ private static final class ImageHeapPatchingState {
133+ static final Word UNINITIALIZED = Word .zero ();
134+ static final Word IN_PROGRESS = Word .unsigned (1 );
135+ static final Word SUCCESSFUL = Word .unsigned (2 );
136+ }
137+
138+ private static final CGlobalData <Word > IMAGE_HEAP_PATCHING_STATE = CGlobalDataFactory .createWord (ImageHeapPatchingState .UNINITIALIZED );
139+
125140 @ Uninterruptible (reason = "Called from uninterruptible code." , mayBeInlined = true )
126141 private static UnsignedWord getLayeredImageHeapAddressSpaceSize () {
127142 // check if value is cached
@@ -167,6 +182,8 @@ protected int initializeLayeredImage(Pointer firstHeapStart, Pointer selfReserve
167182 int result = -1 ;
168183 UnsignedWord remainingSize = initialRemainingSize ;
169184
185+ patchLayeredImageHeap ();
186+
170187 int layerCount = 0 ;
171188 Pointer currentSection = ImageLayerSection .getInitialLayerSection ().get ();
172189 Pointer currentHeapStart = firstHeapStart ;
@@ -213,6 +230,127 @@ protected int initializeLayeredImage(Pointer firstHeapStart, Pointer selfReserve
213230 return result ;
214231 }
215232
233+ /**
234+ * Apply patches to the image heap as specified by each layer. See {@link ImageLayerSection} and
235+ * {@link ImageLayerSectionFeature} for the layout of the section that contains the patches and
236+ * {@link LayeredDispatchTableFeature} where code patches are gathered.
237+ */
238+ @ Uninterruptible (reason = "Thread state not yet set up." )
239+ public static void patchLayeredImageHeap () {
240+ Word heapPatchStateAddr = IMAGE_HEAP_PATCHING_STATE .get ();
241+ boolean firstIsolate = heapPatchStateAddr .logicCompareAndSwapWord (0 , ImageHeapPatchingState .UNINITIALIZED , ImageHeapPatchingState .IN_PROGRESS , NamedLocationIdentity .OFF_HEAP_LOCATION );
242+
243+ if (!firstIsolate ) {
244+ // spin-wait for first isolate
245+ Word state = heapPatchStateAddr .readWordVolatile (0 , NamedLocationIdentity .OFF_HEAP_LOCATION );
246+ while (state .equal (ImageHeapPatchingState .IN_PROGRESS )) {
247+ PauseNode .pause ();
248+ state = heapPatchStateAddr .readWordVolatile (0 , NamedLocationIdentity .OFF_HEAP_LOCATION );
249+ }
250+
251+ /* Patching has already been successfully completed, nothing needs to be done. */
252+ return ;
253+ }
254+
255+ Pointer layerSection = ImageLayerSection .getInitialLayerSection ().get ();
256+ Pointer initialLayerImageHeap = layerSection .readWord (ImageLayerSection .getEntryOffset (HEAP_BEGIN ));
257+ Pointer codeBase = layerSection .readWord (ImageLayerSection .getEntryOffset (CODE_START ));
258+
259+ int referenceSize = ConfigurationValues .getObjectLayout ().getReferenceSize ();
260+ while (layerSection .isNonNull ()) {
261+ Pointer data = layerSection .add (ImageLayerSection .getEntryOffset (VARIABLY_SIZED_DATA ));
262+ int offset = 0 ;
263+
264+ offset = skipSingletonsTable (data , offset , referenceSize );
265+
266+ /* Patch code offsets to become relative to the code base. */
267+ Pointer layerHeapRelocs = layerSection .readWord (ImageLayerSection .getEntryOffset (HEAP_RELOCATABLE_BEGIN ));
268+ Pointer layerCode = layerSection .readWord (ImageLayerSection .getEntryOffset (CODE_START ));
269+ /*
270+ * Note that the code base can be above the layer's code section, in which case the
271+ * subtraction underflows and the additions of code address computations overflow,
272+ * giving the correct result.
273+ */
274+ Word layerCodeOffsetToBase = (Word ) layerCode .subtract (codeBase );
275+ offset = applyLayerCodePointerPatches (data , offset , layerHeapRelocs , layerCodeOffsetToBase );
276+
277+ /* Patch absolute addresses to become relative to the code base. */
278+ Word negativeCodeBase = Word .<Word > zero ().subtract (codeBase );
279+ offset = applyLayerCodePointerPatches (data , offset , layerHeapRelocs , negativeCodeBase );
280+
281+ /* Patch references in the image heap. */
282+ applyLayerImageHeapRefPatches (data .add (offset ), initialLayerImageHeap );
283+
284+ layerSection = layerSection .readWord (ImageLayerSection .getEntryOffset (NEXT_SECTION ));
285+ }
286+
287+ heapPatchStateAddr .writeWordVolatile (0 , ImageHeapPatchingState .SUCCESSFUL );
288+ }
289+
290+ @ Uninterruptible (reason = "Thread state not yet set up." )
291+ private static int skipSingletonsTable (Pointer data , int offset , int referenceSize ) {
292+ long singletonTableEntryCount = data .readLong (offset );
293+ UnsignedWord singletonTableAlignedSize = roundUp (unsigned (singletonTableEntryCount * referenceSize ), unsigned (Long .BYTES ));
294+ return offset + Long .BYTES + UnsignedUtils .safeToInt (singletonTableAlignedSize );
295+ }
296+
297+ @ Uninterruptible (reason = "Thread state not yet set up." )
298+ private static int applyLayerCodePointerPatches (Pointer data , int startOffset , Pointer layerHeapRelocs , Word addend ) {
299+ int wordSize = ConfigurationValues .getTarget ().wordSize ;
300+
301+ int offset = startOffset ;
302+ long bitmapWordCountAsLong = data .readLong (offset );
303+ int bitmapWordCount = UninterruptibleUtils .NumUtil .safeToInt (bitmapWordCountAsLong );
304+ offset += Long .BYTES ;
305+ if (addend .equal (0 )) {
306+ /* Nothing to do. */
307+ offset += bitmapWordCount * Long .BYTES ;
308+ return offset ;
309+ }
310+
311+ for (int i = 0 ; i < bitmapWordCount ; i ++) {
312+ long bits = data .readLong (offset );
313+ offset += Long .BYTES ;
314+ int j = 0 ; // index of a 1-bit
315+ while (bits != 0 ) {
316+ int ntz = UninterruptibleUtils .Long .countTrailingZeros (bits );
317+ j += ntz ;
318+
319+ int at = (i * 64 + j ) * wordSize ;
320+ Word w = layerHeapRelocs .readWord (at );
321+ w = w .add (addend );
322+ layerHeapRelocs .writeWord (at , w );
323+
324+ /*
325+ * Note that we must not shift by ntz+1 here because it can be 64, which would be a
326+ * no-op according to the Java Language Specification, 15.19. Shift Operators.
327+ */
328+ bits = (bits >>> ntz ) >>> 1 ;
329+ j ++;
330+ }
331+ }
332+ return offset ;
333+ }
334+
335+ @ Uninterruptible (reason = "Thread state not yet set up." )
336+ private static void applyLayerImageHeapRefPatches (Pointer patches , Pointer layerImageHeap ) {
337+ int referenceSize = ConfigurationValues .getObjectLayout ().getReferenceSize ();
338+ long countAsLong = patches .readLong (0 );
339+ int count = UninterruptibleUtils .NumUtil .safeToInt (countAsLong );
340+ int offset = Long .BYTES ;
341+ int endOffset = offset + count * Integer .BYTES ;
342+ while (offset < endOffset ) {
343+ int heapOffset = patches .readInt (offset );
344+ int referenceEncoding = patches .readInt (offset + Integer .BYTES );
345+ offset += 2 * Integer .BYTES ;
346+ if (referenceSize == 4 ) {
347+ layerImageHeap .writeInt (heapOffset , referenceEncoding );
348+ } else {
349+ layerImageHeap .writeLong (heapOffset , referenceEncoding );
350+ }
351+ }
352+ }
353+
216354 @ Override
217355 @ Uninterruptible (reason = "Called during isolate initialization." )
218356 public int initialize (Pointer reservedAddressSpace , UnsignedWord reservedSize , WordPointer basePointer , WordPointer endPointer ) {
@@ -262,7 +400,9 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W
262400 basePointer .write (heapBase );
263401 Pointer imageHeapStart = heapBase .add (imageHeapOffsetInAddressSpace );
264402 remainingSize = remainingSize .subtract (imageHeapOffsetInAddressSpace );
265- if (!ImageLayerBuildingSupport .buildingImageLayer ()) {
403+ if (ImageLayerBuildingSupport .buildingImageLayer ()) {
404+ return initializeLayeredImage (imageHeapStart , selfReservedHeapBase , remainingSize , endPointer );
405+ } else {
266406 int result = initializeImageHeap (imageHeapStart , remainingSize , endPointer ,
267407 CACHED_IMAGE_FD .get (), CACHED_IMAGE_HEAP_OFFSET .get (), CACHED_IMAGE_HEAP_RELOCATIONS .get (), MAGIC .get (),
268408 IMAGE_HEAP_BEGIN .get (), IMAGE_HEAP_END .get (),
@@ -272,8 +412,6 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W
272412 freeImageHeap (selfReservedHeapBase );
273413 }
274414 return result ;
275- } else {
276- return initializeLayeredImage (imageHeapStart , selfReservedHeapBase , remainingSize , endPointer );
277415 }
278416 }
279417
0 commit comments