Skip to content

Commit e2da2db

Browse files
A few more fixes.
1 parent 8aa9f26 commit e2da2db

File tree

14 files changed

+94
-82
lines changed

14 files changed

+94
-82
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ This changelog summarizes major changes to GraalVM Native Image.
2525
* (GR-38414) BellSoft implemented the `MemoryPoolMXBean` for the serial and epsilon GCs.
2626
* (GR-40641) Dynamic linking of AWT libraries on Linux.
2727
* (GR-40463) Red Hat added experimental support for JMX, which can be enabled with the `--enable-monitoring` option (e.g. `--enable-monitoring=jmxclient,jmxserver`).
28-
* (GR-42740) Red Hat added experimental support for JFR event streaming.
28+
* (GR-42740) Together with Red Hat, we added experimental support for JFR event streaming.
2929
* (GR-44110) Native Image now targets `x86-64-v3` by default on AMD64 and supports a new `-march` option. Use `-march=compatibility` for best compatibility (previous default) or `-march=native` for best performance if the native executable is deployed on the same machine or on a machine with the same CPU features. To list all available machine types, use `-march=list`.
3030
* (GR-43971) Add native-image option `-E<env-var-key>[=<env-var-value>]` and support environment variable capturing in bundles. Previously almost all environment variables were available in the builder. To temporarily revert back to the old behaviour, env setting `NATIVE_IMAGE_SLOPPY_BUILDER_SANITATION=true` can be used. The old behaviour will be removed in a future release.
3131

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3737
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
3838
import com.oracle.svm.core.annotate.TargetClass;
39+
import com.oracle.svm.core.annotate.TargetElement;
3940

4041
@TargetClass(className = "jdk.internal.platform.cgroupv1.CgroupV1Subsystem", onlyWith = JDK17OrLater.class)
4142
@Platforms(LINUX.class)
@@ -69,6 +70,7 @@ final class Target_jdk_jfr_internal_instrument_JDKEvents {
6970
@Platforms(LINUX.class)
7071
final class Target_jdk_jfr_internal_RequestEngine {
7172
@Alias //
73+
@TargetElement(onlyWith = JDK20OrLater.class) //
7274
@RecomputeFieldValue(kind = Kind.NewInstance, declClass = ReentrantLock.class) //
7375
private static ReentrantLock lock;
7476

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Po
611611

612612
@FunctionalInterface
613613
public interface CharReplacer {
614+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
614615
char replace(char val);
615616
}
616617
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrBufferNodeAccess.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
* Used to access the raw memory of a {@link JfrBufferNode}.
4343
*/
4444
public final class JfrBufferNodeAccess {
45+
private static final byte NONE = 0b00;
4546
private static final byte RETIRED = 0b01;
4647

4748
private JfrBufferNodeAccess() {
@@ -54,6 +55,7 @@ public static JfrBufferNode allocate(JfrBuffer buffer) {
5455
node.setBuffer(buffer);
5556
node.setNext(WordFactory.nullPointer());
5657
node.setLockOwner(WordFactory.nullPointer());
58+
node.setFlags(NONE);
5759
NativeSpinLockUtils.initialize(ptrToLock(node));
5860
}
5961
return node;
@@ -113,6 +115,13 @@ private static CIntPointer ptrToLock(JfrBufferNode node) {
113115
return (CIntPointer) ((Pointer) node).add(JfrBufferNode.offsetOfLock());
114116
}
115117

118+
/**
119+
* The thread-local {@link JfrBuffer}s that are used for Java-level JFR events can't be freed
120+
* when JFR recording is stopped because the JDK class {@code EventWriter} is not
121+
* uninterruptible (i.e., threads could continue using such {@link JfrBuffer}s even after the
122+
* 'StopRecording' safepoint ends). Therefore, we mark those buffers as retired and either free
123+
* or reinstantiate them at a later point in time.
124+
*/
116125
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
117126
public static void setRetired(JfrBufferNode node) {
118127
assert isLockedByCurrentThread(node);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrBufferType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.jfr;
2626

27+
import com.oracle.svm.core.Uninterruptible;
28+
2729
/**
2830
* List of all possible {@link JfrBuffer} types.
2931
*/
@@ -53,6 +55,7 @@ public enum JfrBufferType {
5355
this.threadLocal = threadLocal;
5456
}
5557

58+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
5659
public boolean isThreadLocal() {
5760
return threadLocal;
5861
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrChunkWriter.java

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.graalvm.nativeimage.IsolateThread;
3535
import org.graalvm.nativeimage.Platform;
3636
import org.graalvm.nativeimage.Platforms;
37-
import org.graalvm.word.SignedWord;
3837
import org.graalvm.word.UnsignedWord;
3938
import org.graalvm.word.WordFactory;
4039

@@ -45,6 +44,8 @@
4544
import com.oracle.svm.core.jfr.traceid.JfrTraceIdEpoch;
4645
import com.oracle.svm.core.locks.VMMutex;
4746
import com.oracle.svm.core.os.RawFileOperationSupport;
47+
import com.oracle.svm.core.os.RawFileOperationSupport.FileAccessMode;
48+
import com.oracle.svm.core.os.RawFileOperationSupport.FileCreationMode;
4849
import com.oracle.svm.core.os.RawFileOperationSupport.RawFileDescriptor;
4950
import com.oracle.svm.core.sampler.SamplerBuffersAccess;
5051
import com.oracle.svm.core.thread.JavaVMOperation;
@@ -89,8 +90,8 @@ public final class JfrChunkWriter implements JfrUnlockedChunkWriter {
8990
private boolean newChunk;
9091
private boolean isFinal;
9192
private long lastMetadataId;
92-
private SignedWord metadataPosition;
93-
private SignedWord lastCheckpointOffset;
93+
private long metadataPosition;
94+
private long lastCheckpointOffset;
9495

9596
@Platforms(Platform.HOSTED_ONLY.class)
9697
public JfrChunkWriter(JfrGlobalMemory globalMemory, JfrStackTraceRepository stackTraceRepo, JfrMethodRepository methodRepo, JfrTypeRepository typeRepo, JfrSymbolRepository symbolRepo,
@@ -158,8 +159,8 @@ public void openFile(String outputFile) {
158159
newChunk = true;
159160
isFinal = false;
160161
lastMetadataId = -1;
161-
metadataPosition = WordFactory.signed(-1);
162-
lastCheckpointOffset = WordFactory.signed(-1);
162+
metadataPosition = -1;
163+
lastCheckpointOffset = -1;
163164

164165
writeFileHeader();
165166
}
@@ -169,7 +170,7 @@ public void write(JfrBuffer buffer) {
169170
assert lock.isOwner();
170171
assert buffer.isNonNull();
171172
assert buffer.getBufferType() == JfrBufferType.C_HEAP || VMOperation.isInProgressAtSafepoint() || JfrBufferNodeAccess.isLockedByCurrentThread(buffer.getNode());
172-
assert buffer.getNode() == null || !JfrBufferNodeAccess.isRetired(buffer.getNode());
173+
assert buffer.getNode().isNull() || !JfrBufferNodeAccess.isRetired(buffer.getNode());
173174

174175
UnsignedWord unflushedSize = JfrBufferAccess.getUnflushedSize(buffer);
175176
if (unflushedSize.equal(0)) {
@@ -233,38 +234,37 @@ private void writeFileHeader() {
233234
getFileSupport().write(fd, FILE_MAGIC);
234235
getFileSupport().writeShort(fd, JFR_VERSION_MAJOR);
235236
getFileSupport().writeShort(fd, JFR_VERSION_MINOR);
236-
assert getFileSupport().position(fd).equal(CHUNK_SIZE_OFFSET);
237+
assert getFileSupport().position(fd) == CHUNK_SIZE_OFFSET;
237238
getFileSupport().writeLong(fd, 0L); // chunk size
238239
getFileSupport().writeLong(fd, 0L); // last checkpoint offset
239240
getFileSupport().writeLong(fd, 0L); // metadata position
240241
getFileSupport().writeLong(fd, chunkStartNanos);
241242
getFileSupport().writeLong(fd, 0L); // durationNanos
242243
getFileSupport().writeLong(fd, chunkStartTicks);
243244
getFileSupport().writeLong(fd, JfrTicks.getTicksFrequency());
244-
assert getFileSupport().position(fd).equal(FILE_STATE_OFFSET);
245+
assert getFileSupport().position(fd) == FILE_STATE_OFFSET;
245246
getFileSupport().writeByte(fd, getAndIncrementGeneration());
246247
getFileSupport().writeByte(fd, (byte) 0); // padding
247248
getFileSupport().writeShort(fd, computeHeaderFlags());
248249
}
249250

250251
private void patchFileHeader(boolean flushpoint) {
251252
assert lock.isOwner();
252-
assert metadataPosition.greaterThan(0);
253-
assert lastCheckpointOffset.greaterThan(0);
253+
assert metadataPosition > 0;
254+
assert lastCheckpointOffset > 0;
254255

255256
byte generation = flushpoint ? getAndIncrementGeneration() : COMPLETE;
256-
SignedWord currentPos = getFileSupport().position(fd);
257-
long chunkSize = currentPos.rawValue();
257+
long currentPos = getFileSupport().position(fd);
258258
long durationNanos = JfrTicks.currentTimeNanos() - chunkStartNanos;
259259

260-
getFileSupport().seek(fd, WordFactory.signed(CHUNK_SIZE_OFFSET));
261-
getFileSupport().writeLong(fd, chunkSize);
262-
getFileSupport().writeLong(fd, lastCheckpointOffset.rawValue());
263-
getFileSupport().writeLong(fd, metadataPosition.rawValue());
260+
getFileSupport().seek(fd, CHUNK_SIZE_OFFSET);
261+
getFileSupport().writeLong(fd, currentPos);
262+
getFileSupport().writeLong(fd, lastCheckpointOffset);
263+
getFileSupport().writeLong(fd, metadataPosition);
264264
getFileSupport().writeLong(fd, chunkStartNanos);
265265
getFileSupport().writeLong(fd, durationNanos);
266266

267-
getFileSupport().seek(fd, WordFactory.signed(FILE_STATE_OFFSET));
267+
getFileSupport().seek(fd, FILE_STATE_OFFSET);
268268
getFileSupport().writeByte(fd, generation);
269269
getFileSupport().writeByte(fd, (byte) 0);
270270
getFileSupport().writeShort(fd, computeHeaderFlags());
@@ -308,20 +308,20 @@ private void writeThreadCheckpoint(boolean flushpoint) {
308308
private void writeCheckpointEvent(JfrCheckpointType type, JfrRepository[] repositories, boolean writeSerializers, boolean flushpoint) {
309309
assert lock.isOwner();
310310

311-
SignedWord start = beginEvent();
311+
long start = beginEvent();
312312
writeCompressedLong(JfrReservedEvent.CHECKPOINT.getId());
313313
writeCompressedLong(JfrTicks.elapsedTicks());
314314
writeCompressedLong(0); // duration
315315
writeCompressedLong(getDeltaToLastCheckpoint(start));
316316
writeByte(type.getId());
317317

318-
SignedWord poolCountPos = getFileSupport().position(fd);
318+
long poolCountPos = getFileSupport().position(fd);
319319
getFileSupport().writeInt(fd, 0); // pool count (patched below)
320320

321321
int poolCount = writeSerializers ? writeSerializers() : 0;
322322
poolCount += writeConstantPools(repositories, flushpoint);
323323

324-
SignedWord currentPos = getFileSupport().position(fd);
324+
long currentPos = getFileSupport().position(fd);
325325
getFileSupport().seek(fd, poolCountPos);
326326
writePaddedInt(poolCount);
327327

@@ -331,11 +331,11 @@ private void writeCheckpointEvent(JfrCheckpointType type, JfrRepository[] reposi
331331
lastCheckpointOffset = start;
332332
}
333333

334-
private long getDeltaToLastCheckpoint(SignedWord startOfNewCheckpoint) {
335-
if (lastCheckpointOffset.lessThan(0)) {
334+
private long getDeltaToLastCheckpoint(long startOfNewCheckpoint) {
335+
if (lastCheckpointOffset < 0) {
336336
return 0L;
337337
}
338-
return lastCheckpointOffset.subtract(startOfNewCheckpoint).rawValue();
338+
return lastCheckpointOffset - startOfNewCheckpoint;
339339
}
340340

341341
private int writeSerializers() {
@@ -367,7 +367,7 @@ private void writeMetadataEvent() {
367367
return;
368368
}
369369

370-
SignedWord start = beginEvent();
370+
long start = beginEvent();
371371
writeCompressedLong(JfrReservedEvent.METADATA.getId());
372372
writeCompressedLong(JfrTicks.elapsedTicks());
373373
writeCompressedLong(0); // duration
@@ -381,25 +381,25 @@ private void writeMetadataEvent() {
381381

382382
public boolean shouldRotateDisk() {
383383
assert lock.isOwner();
384-
return getFileSupport().isValid(fd) && getFileSupport().size(fd).greaterThan(WordFactory.signed(notificationThreshold));
384+
return getFileSupport().isValid(fd) && getFileSupport().size(fd) > notificationThreshold;
385385
}
386386

387387
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
388-
public SignedWord beginEvent() {
389-
SignedWord start = getFileSupport().position(fd);
388+
public long beginEvent() {
389+
long start = getFileSupport().position(fd);
390390
// Write a placeholder for the size. Will be patched by endEvent,
391391
getFileSupport().writeInt(fd, 0);
392392
return start;
393393
}
394394

395395
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
396-
public void endEvent(SignedWord start) {
397-
SignedWord end = getFileSupport().position(fd);
398-
SignedWord writtenBytes = end.subtract(start);
399-
assert (int) writtenBytes.rawValue() == writtenBytes.rawValue();
396+
public void endEvent(long start) {
397+
long end = getFileSupport().position(fd);
398+
long writtenBytes = end - start;
399+
assert (int) writtenBytes == writtenBytes;
400400

401401
getFileSupport().seek(fd, start);
402-
writePaddedInt(writtenBytes.rawValue());
402+
writePaddedInt(writtenBytes);
403403
getFileSupport().seek(fd, end);
404404
}
405405

@@ -520,8 +520,8 @@ private void traverseThreadLocalBuffers(JfrBufferList list, boolean flushpoint)
520520

521521
while (node.isNonNull()) {
522522
JfrBufferNode next = node.getNext();
523-
boolean success = JfrBufferNodeAccess.tryLock(node);
524-
if (success) {
523+
boolean lockAcquired = JfrBufferNodeAccess.tryLock(node);
524+
if (lockAcquired) {
525525
JfrBuffer buffer = JfrBufferNodeAccess.getBuffer(node);
526526
if (buffer.isNull()) {
527527
list.removeNode(node, prev);
@@ -530,9 +530,9 @@ private void traverseThreadLocalBuffers(JfrBufferList list, boolean flushpoint)
530530
continue;
531531
}
532532

533-
/* Skip retired nodes as they may contain invalid data. */
534-
if (!JfrBufferNodeAccess.isRetired(node)) {
535-
try {
533+
try {
534+
/* Skip retired nodes as they may contain invalid data. */
535+
if (!JfrBufferNodeAccess.isRetired(node)) {
536536
if (flushpoint) {
537537
/*
538538
* I/O operations may be slow, so this flushes to the global buffers
@@ -548,13 +548,13 @@ private void traverseThreadLocalBuffers(JfrBufferList list, boolean flushpoint)
548548
* reinitialize the thread-local buffers as the individual threads will
549549
* handle space reclamation on their own time.
550550
*/
551-
} finally {
552-
JfrBufferNodeAccess.unlock(node);
553551
}
552+
} finally {
553+
JfrBufferNodeAccess.unlock(node);
554554
}
555555
}
556556

557-
assert success || flushpoint;
557+
assert lockAcquired || flushpoint;
558558
prev = node;
559559
node = next;
560560
}
@@ -565,8 +565,8 @@ private void flushGlobalMemory(boolean flushpoint) {
565565
JfrBufferList buffers = globalMemory.getBuffers();
566566
JfrBufferNode node = buffers.getHead();
567567
while (node.isNonNull()) {
568-
boolean success = JfrBufferNodeAccess.tryLock(node);
569-
if (success) {
568+
boolean lockAcquired = JfrBufferNodeAccess.tryLock(node);
569+
if (lockAcquired) {
570570
try {
571571
JfrBuffer buffer = JfrBufferNodeAccess.getBuffer(node);
572572
write(buffer);
@@ -575,7 +575,7 @@ private void flushGlobalMemory(boolean flushpoint) {
575575
JfrBufferNodeAccess.unlock(node);
576576
}
577577
}
578-
assert success || flushpoint;
578+
assert lockAcquired || flushpoint;
579579
node = node.getNext();
580580
}
581581
}
@@ -647,7 +647,7 @@ private void changeEpoch() {
647647
* accessing the currently active buffers of other threads.
648648
*/
649649
@Uninterruptible(reason = "Prevent JFR recording.")
650-
private void processSamplerBuffers() {
650+
private static void processSamplerBuffers() {
651651
assert VMOperation.isInProgressAtSafepoint();
652652
assert ThreadingSupportImpl.isRecurringCallbackPaused();
653653

@@ -660,7 +660,7 @@ private void processSamplerBuffers() {
660660
}
661661

662662
@Uninterruptible(reason = "Prevent JFR recording.")
663-
private void processSamplerBuffers0() {
663+
private static void processSamplerBuffers0() {
664664
SamplerBuffersAccess.processActiveBuffers();
665665
SamplerBuffersAccess.processFullBuffers(false);
666666
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEventWriterAccess.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.jfr;
2626

27+
import java.lang.reflect.Field;
28+
2729
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
2830
import org.graalvm.nativeimage.Platform;
2931
import org.graalvm.nativeimage.Platforms;
@@ -43,11 +45,11 @@ public final class JfrEventWriterAccess {
4345
* The fields "startPosition" and "startPositionAddress" in the JDK class EventWriter refer to
4446
* the committed position and not to the start of the buffer.
4547
*/
46-
private static final long COMMITTED_POSITION_OFFSET = U.objectFieldOffset(getEventWriterClass(), "startPosition");
47-
private static final long COMMITTED_POSITION_ADDRESS_OFFSET = U.objectFieldOffset(getEventWriterClass(), "startPositionAddress");
48-
private static final long CURRENT_POSITION_OFFSET = U.objectFieldOffset(getEventWriterClass(), "currentPosition");
49-
private static final long MAX_POSITION_OFFSET = U.objectFieldOffset(getEventWriterClass(), "maxPosition");
50-
private static final long VALID_OFFSET = U.objectFieldOffset(getEventWriterClass(), "valid");
48+
private static final Field COMMITTED_POSITION_FIELD = ReflectionUtil.lookupField(getEventWriterClass(), "startPosition");
49+
private static final Field COMMITTED_POSITION_ADDRESS_FIELD = ReflectionUtil.lookupField(getEventWriterClass(), "startPositionAddress");
50+
private static final Field CURRENT_POSITION_FIELD = ReflectionUtil.lookupField(getEventWriterClass(), "currentPosition");
51+
private static final Field MAX_POSITION_FIELD = ReflectionUtil.lookupField(getEventWriterClass(), "maxPosition");
52+
private static final Field VALID_FIELD = ReflectionUtil.lookupField(getEventWriterClass(), "valid");
5153

5254
@Platforms(Platform.HOSTED_ONLY.class)
5355
private JfrEventWriterAccess() {
@@ -89,10 +91,10 @@ public static void update(Target_jdk_jfr_internal_EventWriter writer, JfrBuffer
8991
Pointer currentPos = committedPos.add(uncommittedSize);
9092
Pointer maxPos = JfrBufferAccess.getDataEnd(buffer);
9193

92-
U.putLong(writer, COMMITTED_POSITION_OFFSET, committedPos.rawValue());
93-
U.putLong(writer, COMMITTED_POSITION_ADDRESS_OFFSET, addressOfCommittedPos.rawValue());
94-
U.putLong(writer, CURRENT_POSITION_OFFSET, currentPos.rawValue());
95-
U.putLong(writer, MAX_POSITION_OFFSET, maxPos.rawValue());
94+
U.putLong(writer, U.objectFieldOffset(COMMITTED_POSITION_FIELD), committedPos.rawValue());
95+
U.putLong(writer, U.objectFieldOffset(COMMITTED_POSITION_ADDRESS_FIELD), addressOfCommittedPos.rawValue());
96+
U.putLong(writer, U.objectFieldOffset(CURRENT_POSITION_FIELD), currentPos.rawValue());
97+
U.putLong(writer, U.objectFieldOffset(MAX_POSITION_FIELD), maxPos.rawValue());
9698
if (!valid) {
9799
markAsInvalid(writer);
98100
}
@@ -101,6 +103,6 @@ public static void update(Target_jdk_jfr_internal_EventWriter writer, JfrBuffer
101103
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
102104
public static void markAsInvalid(Target_jdk_jfr_internal_EventWriter writer) {
103105
/* The VM should never write true (only the JDK code may do that). */
104-
U.putBooleanVolatile(writer, VALID_OFFSET, false);
106+
U.putBooleanVolatile(writer, U.objectFieldOffset(VALID_FIELD), false);
105107
}
106108
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* added data when it tries to iterate the data at a safepoint.
3434
*
3535
* Some repositories (e.g., {@link JfrTypeRepository}) return stable JFR trace IDs (i.e., the trace
36-
* id does not change if the epoch changes). However, the corresponding data (e.g., the type) is
36+
* ID does not change if the epoch changes). However, the corresponding data (e.g., the type) is
3737
* only marked as used in a certain epoch, so callers must always be aware that the returned trace
3838
* ID is only valid for a specific epoch, no matter if the trace ID is stable or not.
3939
*/

0 commit comments

Comments
 (0)