33
33
import static com .oracle .svm .core .Isolates .IMAGE_HEAP_WRITABLE_END ;
34
34
import static com .oracle .svm .core .Isolates .IMAGE_HEAP_WRITABLE_PATCHED_BEGIN ;
35
35
import static com .oracle .svm .core .Isolates .IMAGE_HEAP_WRITABLE_PATCHED_END ;
36
+ import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .CODE_START ;
36
37
import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_BEGIN ;
37
38
import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_END ;
38
39
import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_RELOCATABLE_BEGIN ;
42
43
import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_WRITEABLE_PATCHED_BEGIN ;
43
44
import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .HEAP_WRITEABLE_PATCHED_END ;
44
45
import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .NEXT_SECTION ;
46
+ import static com .oracle .svm .core .imagelayer .ImageLayerSection .SectionEntries .VARIABLY_SIZED_DATA ;
45
47
import static com .oracle .svm .core .posix .linux .ProcFSSupport .findMapping ;
46
48
import static com .oracle .svm .core .util .PointerUtils .roundDown ;
47
49
import static com .oracle .svm .core .util .UnsignedUtils .isAMultiple ;
48
50
import static com .oracle .svm .core .util .UnsignedUtils .roundUp ;
49
51
import static jdk .graal .compiler .word .Word .signed ;
52
+ import static jdk .graal .compiler .word .Word .unsigned ;
50
53
51
54
import java .util .concurrent .ThreadLocalRandom ;
52
55
71
74
import com .oracle .svm .core .heap .Heap ;
72
75
import com .oracle .svm .core .imagelayer .ImageLayerBuildingSupport ;
73
76
import com .oracle .svm .core .imagelayer .ImageLayerSection ;
77
+ import com .oracle .svm .core .jdk .UninterruptibleUtils ;
74
78
import com .oracle .svm .core .os .AbstractImageHeapProvider ;
75
79
import com .oracle .svm .core .os .VirtualMemoryProvider ;
76
80
import com .oracle .svm .core .os .VirtualMemoryProvider .Access ;
81
85
import com .oracle .svm .core .util .PointerUtils ;
82
86
import com .oracle .svm .core .util .UnsignedUtils ;
83
87
import com .oracle .svm .core .util .VMError ;
88
+ import com .oracle .svm .hosted .imagelayer .ImageLayerSectionFeature ;
89
+ import com .oracle .svm .hosted .imagelayer .LayeredDispatchTableFeature ;
84
90
91
+ import jdk .graal .compiler .nodes .NamedLocationIdentity ;
85
92
import jdk .graal .compiler .nodes .PauseNode ;
86
93
import jdk .graal .compiler .word .Word ;
87
94
@@ -122,6 +129,14 @@ public class LinuxImageHeapProvider extends AbstractImageHeapProvider {
122
129
*/
123
130
static final CGlobalData <WordPointer > CACHED_LAYERED_IMAGE_HEAP_ADDRESS_SPACE_SIZE = CGlobalDataFactory .createWord ();
124
131
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
+
125
140
@ Uninterruptible (reason = "Called from uninterruptible code." , mayBeInlined = true )
126
141
private static UnsignedWord getLayeredImageHeapAddressSpaceSize () {
127
142
// check if value is cached
@@ -167,6 +182,8 @@ protected int initializeLayeredImage(Pointer firstHeapStart, Pointer selfReserve
167
182
int result = -1 ;
168
183
UnsignedWord remainingSize = initialRemainingSize ;
169
184
185
+ patchLayeredImageHeap ();
186
+
170
187
int layerCount = 0 ;
171
188
Pointer currentSection = ImageLayerSection .getInitialLayerSection ().get ();
172
189
Pointer currentHeapStart = firstHeapStart ;
@@ -213,6 +230,127 @@ protected int initializeLayeredImage(Pointer firstHeapStart, Pointer selfReserve
213
230
return result ;
214
231
}
215
232
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
+
216
354
@ Override
217
355
@ Uninterruptible (reason = "Called during isolate initialization." )
218
356
public int initialize (Pointer reservedAddressSpace , UnsignedWord reservedSize , WordPointer basePointer , WordPointer endPointer ) {
@@ -262,7 +400,9 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W
262
400
basePointer .write (heapBase );
263
401
Pointer imageHeapStart = heapBase .add (imageHeapOffsetInAddressSpace );
264
402
remainingSize = remainingSize .subtract (imageHeapOffsetInAddressSpace );
265
- if (!ImageLayerBuildingSupport .buildingImageLayer ()) {
403
+ if (ImageLayerBuildingSupport .buildingImageLayer ()) {
404
+ return initializeLayeredImage (imageHeapStart , selfReservedHeapBase , remainingSize , endPointer );
405
+ } else {
266
406
int result = initializeImageHeap (imageHeapStart , remainingSize , endPointer ,
267
407
CACHED_IMAGE_FD .get (), CACHED_IMAGE_HEAP_OFFSET .get (), CACHED_IMAGE_HEAP_RELOCATIONS .get (), MAGIC .get (),
268
408
IMAGE_HEAP_BEGIN .get (), IMAGE_HEAP_END .get (),
@@ -272,8 +412,6 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W
272
412
freeImageHeap (selfReservedHeapBase );
273
413
}
274
414
return result ;
275
- } else {
276
- return initializeLayeredImage (imageHeapStart , selfReservedHeapBase , remainingSize , endPointer );
277
415
}
278
416
}
279
417
0 commit comments