Skip to content

Commit b12f195

Browse files
committed
Address review comments.
1 parent 36fd2b5 commit b12f195

File tree

11 files changed

+116
-92
lines changed

11 files changed

+116
-92
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boo
118118
}
119119

120120
private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean immutable, boolean hasRelocatables, boolean patched) {
121+
if (patched && hasRelocatables) {
122+
throw VMError.shouldNotReachHere("Object cannot contain both relocatables and patched constants: " + info.getObject());
123+
}
121124
if (patched) {
122125
return getWritablePatched();
123126
} else if (immutable) {

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import com.oracle.svm.core.heap.Heap;
7575
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
7676
import com.oracle.svm.core.imagelayer.ImageLayerSection;
77+
import com.oracle.svm.core.jdk.UninterruptibleUtils;
7778
import com.oracle.svm.core.os.AbstractImageHeapProvider;
7879
import com.oracle.svm.core.os.VirtualMemoryProvider;
7980
import com.oracle.svm.core.os.VirtualMemoryProvider.Access;
@@ -84,10 +85,11 @@
8485
import com.oracle.svm.core.util.PointerUtils;
8586
import com.oracle.svm.core.util.UnsignedUtils;
8687
import com.oracle.svm.core.util.VMError;
88+
import com.oracle.svm.hosted.imagelayer.ImageLayerSectionFeature;
89+
import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableFeature;
8790

8891
import jdk.graal.compiler.nodes.NamedLocationIdentity;
8992
import jdk.graal.compiler.nodes.PauseNode;
90-
import jdk.graal.compiler.replacements.nodes.CountTrailingZerosNode;
9193
import jdk.graal.compiler.word.Word;
9294

9395
/**
@@ -133,7 +135,7 @@ private static final class ImageHeapPatchingState {
133135
static final Word SUCCESSFUL = Word.unsigned(2);
134136
}
135137

136-
private static final CGlobalData<Word> IMAGE_HEAP_PATCHING_STATE = CGlobalDataFactory.createWord();
138+
private static final CGlobalData<Word> IMAGE_HEAP_PATCHING_STATE = CGlobalDataFactory.createWord(ImageHeapPatchingState.UNINITIALIZED);
137139

138140
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
139141
private static UnsignedWord getLayeredImageHeapAddressSpaceSize() {
@@ -228,17 +230,22 @@ protected int initializeLayeredImage(Pointer firstHeapStart, Pointer selfReserve
228230
return result;
229231
}
230232

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+
*/
231238
@Uninterruptible(reason = "Thread state not yet set up.")
232239
public static void patchLayeredImageHeap() {
233240
Word heapPatchStateAddr = IMAGE_HEAP_PATCHING_STATE.get();
234241
boolean firstIsolate = heapPatchStateAddr.logicCompareAndSwapWord(0, ImageHeapPatchingState.UNINITIALIZED, ImageHeapPatchingState.IN_PROGRESS, NamedLocationIdentity.OFF_HEAP_LOCATION);
235242

236243
if (!firstIsolate) {
237244
// spin-wait for first isolate
238-
Word state = heapPatchStateAddr.readWordVolatile(0, LocationIdentity.ANY_LOCATION);
245+
Word state = heapPatchStateAddr.readWordVolatile(0, NamedLocationIdentity.OFF_HEAP_LOCATION);
239246
while (state.equal(ImageHeapPatchingState.IN_PROGRESS)) {
240247
PauseNode.pause();
241-
state = heapPatchStateAddr.readWordVolatile(0, LocationIdentity.ANY_LOCATION);
248+
state = heapPatchStateAddr.readWordVolatile(0, NamedLocationIdentity.OFF_HEAP_LOCATION);
242249
}
243250

244251
/* Patching has already been successfully completed, nothing needs to be done. */
@@ -254,19 +261,24 @@ public static void patchLayeredImageHeap() {
254261
Pointer data = layerSection.add(ImageLayerSection.getEntryOffset(VARIABLY_SIZED_DATA));
255262
int offset = 0;
256263

257-
// Skip singletons table
258-
long singletonTableEntryCount = data.readLong(offset);
259-
UnsignedWord singletonTableAlignedSize = roundUp(unsigned(singletonTableEntryCount * referenceSize), unsigned(Long.BYTES));
260-
offset += Long.BYTES + (int) singletonTableAlignedSize.rawValue();
264+
offset = skipSingletonsTable(data, offset, referenceSize);
261265

266+
/* Patch code offsets to become relative to the code base. */
262267
Pointer layerHeapRelocs = layerSection.readWord(ImageLayerSection.getEntryOffset(HEAP_RELOCATABLE_BEGIN));
263268
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+
*/
264274
Word layerCodeOffsetToBase = (Word) layerCode.subtract(codeBase);
265275
offset = applyLayerCodePointerPatches(data, offset, layerHeapRelocs, layerCodeOffsetToBase);
266276

277+
/* Patch absolute addresses to become relative to the code base. */
267278
Word negativeCodeBase = Word.<Word> zero().subtract(codeBase);
268279
offset = applyLayerCodePointerPatches(data, offset, layerHeapRelocs, negativeCodeBase);
269280

281+
/* Patch references in the image heap. */
270282
applyLayerImageHeapRefPatches(data.add(offset), initialLayerImageHeap);
271283

272284
layerSection = layerSection.readWord(ImageLayerSection.getEntryOffset(NEXT_SECTION));
@@ -275,14 +287,23 @@ public static void patchLayeredImageHeap() {
275287
heapPatchStateAddr.writeWordVolatile(0, ImageHeapPatchingState.SUCCESSFUL);
276288
}
277289

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+
278297
@Uninterruptible(reason = "Thread state not yet set up.")
279298
private static int applyLayerCodePointerPatches(Pointer data, int startOffset, Pointer layerHeapRelocs, Word addend) {
280299
int wordSize = ConfigurationValues.getTarget().wordSize;
281300

282301
int offset = startOffset;
283-
int bitmapWordCount = (int) data.readLong(offset);
302+
long bitmapWordCountAsLong = data.readLong(offset);
303+
int bitmapWordCount = UninterruptibleUtils.NumUtil.safeToInt(bitmapWordCountAsLong);
284304
offset += Long.BYTES;
285305
if (addend.equal(0)) {
306+
/* Nothing to do. */
286307
offset += bitmapWordCount * Long.BYTES;
287308
return offset;
288309
}
@@ -292,7 +313,7 @@ private static int applyLayerCodePointerPatches(Pointer data, int startOffset, P
292313
offset += Long.BYTES;
293314
int j = 0; // index of a 1-bit
294315
while (bits != 0) {
295-
int ntz = CountTrailingZerosNode.countLongTrailingZeros(bits);
316+
int ntz = UninterruptibleUtils.Long.countTrailingZeros(bits);
296317
j += ntz;
297318

298319
int at = (i * 64 + j) * wordSize;
@@ -301,11 +322,8 @@ private static int applyLayerCodePointerPatches(Pointer data, int startOffset, P
301322
layerHeapRelocs.writeWord(at, w);
302323

303324
/*
304-
* Note that we must not shift by ntz+1 here because it can be 64, and according to
305-
* the Java Language Specification, 15.19. Shift Operators: If the promoted type of
306-
* the left-hand operand is long, then only the six lowest-order bits of the
307-
* right-hand operand are used as the shift distance. [..] The shift distance
308-
* actually used is therefore always in the range 0 to 63, inclusive.
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.
309327
*/
310328
bits = (bits >>> ntz) >>> 1;
311329
j++;
@@ -317,7 +335,8 @@ private static int applyLayerCodePointerPatches(Pointer data, int startOffset, P
317335
@Uninterruptible(reason = "Thread state not yet set up.")
318336
private static void applyLayerImageHeapRefPatches(Pointer patches, Pointer layerImageHeap) {
319337
int referenceSize = ConfigurationValues.getObjectLayout().getReferenceSize();
320-
int count = (int) patches.readLong(0);
338+
long countAsLong = patches.readLong(0);
339+
int count = UninterruptibleUtils.NumUtil.safeToInt(countAsLong);
321340
int offset = Long.BYTES;
322341
int endOffset = offset + count * Integer.BYTES;
323342
while (offset < endOffset) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/ImageLayerSection.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333

3434
import jdk.graal.compiler.api.replacements.Fold;
3535

36+
/**
37+
* With layered images, this is a section that each layer has and that is present at runtime. It
38+
* contains the addresses of various important locations and information about values to patch at
39+
* runtime. See {@code ImageLayerSectionFeature} for details.
40+
*/
3641
public abstract class ImageLayerSection implements LayeredImageSingleton {
3742

3843
protected final CGlobalData<Pointer> initialSectionStart;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleUtils.java

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.svm.core.util.VMError;
3737

3838
import jdk.graal.compiler.core.common.SuppressFBWarnings;
39+
import jdk.graal.compiler.replacements.nodes.CountTrailingZerosNode;
3940
import jdk.graal.compiler.word.Word;
4041
import jdk.internal.misc.Unsafe;
4142

@@ -501,26 +502,10 @@ public static int toUnsignedInt(byte x) {
501502
}
502503

503504
public static class Long {
504-
/** Uninterruptible version of {@link java.lang.Long#numberOfLeadingZeros(long)}. */
505-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
506-
// Checkstyle: stop
507-
public static int numberOfLeadingZeros(long i) {
508-
// @formatter:off
509-
// HD, Figure 5-6
510-
if (i == 0)
511-
return 64;
512-
int n = 1;
513-
int x = (int)(i >>> 32);
514-
if (x == 0) { n += 32; x = (int)i; }
515-
if (x >>> 16 == 0) { n += 16; x <<= 16; }
516-
if (x >>> 24 == 0) { n += 8; x <<= 8; }
517-
if (x >>> 28 == 0) { n += 4; x <<= 4; }
518-
if (x >>> 30 == 0) { n += 2; x <<= 2; }
519-
n -= x >>> 31;
520-
return n;
521-
// @formatter:on
522-
}
523-
// Checkstyle: resume
505+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
506+
public static int countTrailingZeros(long i) {
507+
return CountTrailingZerosNode.countLongTrailingZeros(i);
508+
}
524509

525510
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
526511
public static int hashCode(long value) {
@@ -529,41 +514,6 @@ public static int hashCode(long value) {
529514
}
530515

531516
public static class Integer {
532-
// Checkstyle: stop
533-
/** Uninterruptible version of {@link java.lang.Integer#numberOfLeadingZeros(int)}. */
534-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
535-
@SuppressWarnings("all")
536-
public static int numberOfLeadingZeros(int i) {
537-
// @formatter:off
538-
// HD, Figure 5-6
539-
if (i == 0)
540-
return 32;
541-
int n = 1;
542-
if (i >>> 16 == 0) { n += 16; i <<= 16; }
543-
if (i >>> 24 == 0) { n += 8; i <<= 8; }
544-
if (i >>> 28 == 0) { n += 4; i <<= 4; }
545-
if (i >>> 30 == 0) { n += 2; i <<= 2; }
546-
n -= i >>> 31;
547-
return n;
548-
// @formatter:on
549-
}
550-
551-
/** Uninterruptible version of {@link java.lang.Integer#highestOneBit(int)}. */
552-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
553-
@SuppressWarnings("all")
554-
public static int highestOneBit(int i) {
555-
// @formatter:off
556-
// HD, Figure 3-1
557-
i |= (i >> 1);
558-
i |= (i >> 2);
559-
i |= (i >> 4);
560-
i |= (i >> 8);
561-
i |= (i >> 16);
562-
return i - (i >>> 1);
563-
// @formatter:on
564-
}
565-
// Checkstyle: resume
566-
567517
/** Uninterruptible version of {@link java.lang.Integer#compare(int, int)}. */
568518
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
569519
public static int compare(int x, int y) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import com.oracle.svm.core.BuildArtifacts.ArtifactType;
7878
import com.oracle.svm.core.BuildPhaseProvider;
7979
import com.oracle.svm.core.FrameAccess;
80+
import com.oracle.svm.core.FunctionPointerHolder;
8081
import com.oracle.svm.core.InvalidMethodPointerHandler;
8182
import com.oracle.svm.core.Isolates;
8283
import com.oracle.svm.core.OS;
@@ -93,13 +94,17 @@
9394
import com.oracle.svm.core.graal.code.CGlobalDataReference;
9495
import com.oracle.svm.core.graal.nodes.TLABObjectHeaderConstant;
9596
import com.oracle.svm.core.heap.Heap;
97+
import com.oracle.svm.core.hub.DynamicHub;
9698
import com.oracle.svm.core.image.ImageHeapLayoutInfo;
9799
import com.oracle.svm.core.image.ImageHeapPartition;
98100
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
99101
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
102+
import com.oracle.svm.core.jni.access.JNIAccessibleMethod;
100103
import com.oracle.svm.core.meta.MethodOffset;
101104
import com.oracle.svm.core.meta.MethodPointer;
102105
import com.oracle.svm.core.option.SubstrateOptionsParser;
106+
import com.oracle.svm.core.os.ImageHeapProvider;
107+
import com.oracle.svm.core.reflect.SubstrateAccessor;
103108
import com.oracle.svm.core.util.UserError;
104109
import com.oracle.svm.core.util.VMError;
105110
import com.oracle.svm.hosted.DeadlockWatchdog;
@@ -557,7 +562,11 @@ public void build(String imageName, DebugContext debug) {
557562
LayeredDispatchTableFeature.singleton().defineDispatchTableSlotSymbols(objectFile, textSection, codeCache, metaAccess);
558563
}
559564

560-
// Mark the sections with the relocations from the maps.
565+
/*
566+
* Mark locations that depend on the memory address of code (text), data, or the heap at
567+
* runtime. These typically generate relocation entries which are processed by the
568+
* dynamic linker. Additional such locations might be marked somewhere else.
569+
*/
561570
markRelocationSitesFromBuffer(textBuffer, textImpl);
562571
markRelocationSitesFromBuffer(roDataBuffer, roDataImpl);
563572
markRelocationSitesFromBuffer(rwDataBuffer, rwDataImpl);
@@ -586,7 +595,7 @@ public void markRelocationSitesFromBuffer(RelocatableBuffer buffer, ProgbitsSect
586595

587596
Object target = info.getTargetObject();
588597
if (target instanceof CFunctionPointer || target instanceof MethodOffset) {
589-
markCodeRelocationSite(sectionImpl, offset, info);
598+
markSiteOfRelocationToCode(sectionImpl, offset, info);
590599
} else {
591600
if (sectionImpl.getElement() == textSection) {
592601
markDataRelocationSiteFromText(buffer, sectionImpl, offset, info);
@@ -631,8 +640,30 @@ private static boolean checkCodeRelocationKind(Info info) {
631640
return (relocationSize == wordSize && RelocationKind.isDirect(relocationKind)) || (relocationSize == 4 && RelocationKind.isPCRelative(relocationKind));
632641
}
633642

634-
/** @see NativeImageHeapWriter#writeConstant */
635-
private void markCodeRelocationSite(final ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) {
643+
/**
644+
* Mark a location that needs to be patched by the dynamic linker at runtime to reflect the
645+
* address where code has been loaded.
646+
*
647+
* {@linkplain DynamicHub Virtual dispatch tables} typically make up the vast majority of such
648+
* locations. Frequent other locations to patch are in {@linkplain SubstrateAccessor reflection
649+
* accessors}, {@linkplain JNIAccessibleMethod JNI accessors} and in
650+
* {@link FunctionPointerHolder}.
651+
*
652+
* With {@link SubstrateOptions#RelativeCodePointers}, virtual dispatch tables contain offsets
653+
* relative to a code base address and so do not need to be patched at runtime, which also
654+
* avoids the cost of private copies of memory pages with the patched values.
655+
*
656+
* With code offsets and layered images, however, the code base refers only to the initial
657+
* layer's code section, so we patch offsets to code from other layers to become relative to
658+
* that code base ourselves at runtime. We do so in our own code without using the dynamic
659+
* linker. See {@link LayeredDispatchTableFeature} which gathers these locations and
660+
* {@link ImageLayerSectionFeature} which provides them for patching in the
661+
* {@link ImageHeapProvider} at runtime.
662+
*
663+
* {@link NativeImageHeap#isRelocatableValue} and {@link NativeImageHeapWriter#writeConstant}
664+
* determine (for the image heap) whether a code reference requires a linker relocation here.
665+
*/
666+
private void markSiteOfRelocationToCode(final ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) {
636667
Object targetObject = info.getTargetObject();
637668
assert targetObject instanceof MethodPointer || targetObject instanceof MethodOffset : "Wrong type for code relocation: " + targetObject.toString();
638669

@@ -659,16 +690,19 @@ private void markCodeRelocationSite(final ProgbitsSectionImpl sectionImpl, final
659690
}
660691
}
661692

693+
/**
694+
* Whether a method has not been compiled in the current image build, and with layered images,
695+
* not in a prior layer, but might be compiled in a future layer.
696+
*/
662697
static boolean isInjectedNotCompiled(HostedMethod target) {
663698
return !target.isCompiled() && !target.isCompiledInPriorLayer();
664699
}
665700

666-
static HostedMethod getMethodRefTargetMethod(HostedMetaAccess metaAccess, ResolvedJavaMethod method) {
667-
HostedMethod target = (method instanceof HostedMethod) ? (HostedMethod) method : metaAccess.getUniverse().lookup(method);
668-
if (isInjectedNotCompiled(target)) {
669-
target = metaAccess.lookupJavaMethod(InvalidMethodPointerHandler.METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD);
701+
static HostedMethod getMethodRefTargetMethod(HostedMetaAccess metaAccess, HostedMethod method) {
702+
if (isInjectedNotCompiled(method)) {
703+
return metaAccess.lookupJavaMethod(InvalidMethodPointerHandler.METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD);
670704
}
671-
return target;
705+
return method;
672706
}
673707

674708
private static boolean isAddendAligned(Architecture arch, long addend, RelocationKind kind) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,22 +258,20 @@ private RelocatedPointer prepareRelocatable(ObjectInfo info, JavaConstant value)
258258

259259
/**
260260
* @see NativeImageHeap#isRelocatableValue
261-
* @see NativeImage#markCodeRelocationSite
261+
* @see NativeImage#markSiteOfRelocationToCode
262262
*/
263263
private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, Object constantValue, ObjectInfo info) {
264264
Object value = constantValue;
265265
if (value instanceof MethodOffset methodOffset) {
266266
HostedMetaAccess metaAccess = heap.hMetaAccess;
267267
ResolvedJavaMethod method = methodOffset.getMethod();
268-
if (!(method instanceof HostedMethod)) {
269-
method = metaAccess.getUniverse().lookup(method);
270-
}
271-
if (imageLayer && NativeImage.isInjectedNotCompiled((HostedMethod) method)) {
268+
HostedMethod hMethod = (method instanceof HostedMethod hm) ? hm : metaAccess.getUniverse().lookup(method);
269+
if (imageLayer && NativeImage.isInjectedNotCompiled(hMethod)) {
272270
// Will be patched in a future layer (even if it ends up not being compiled at all)
273271
addWordConstantRelocation(buffer, index, methodOffset);
274272
return;
275273
}
276-
HostedMethod target = NativeImage.getMethodRefTargetMethod(metaAccess, method);
274+
HostedMethod target = NativeImage.getMethodRefTargetMethod(metaAccess, hMethod);
277275
value = target.getCodeAddressOffset();
278276
} else if (value instanceof RelocatedPointer relocatedPointer) {
279277
addWordConstantRelocation(buffer, index, relocatedPointer);

0 commit comments

Comments
 (0)