From 1356cd29117caa2538d80d92fbb117be5d94c350 Mon Sep 17 00:00:00 2001
Date: Sat, 23 May 2026 15:07:00 +0800
Subject: Compilecommand support dontprediction

---
 src/hotspot/share/compiler/compilerOracle.cpp            | 4 ++++
 src/hotspot/share/compiler/compilerOracle.hpp            | 4 ++++
 src/hotspot/share/jfr/metadata/metadata.xml              | 1 +
 src/hotspot/share/jfr/periodic/jfrPeriodic.cpp           | 3 +++
 src/hotspot/share/opto/parse2.cpp                        | 9 +++++++++
 src/hotspot/share/services/diagnosticArgument.cpp        | 1 +
 src/jdk.jfr/share/classes/jdk/jfr/Recording.java         | 8 ++++++++
 .../share/classes/jdk/jfr/consumer/RecordingStream.java  | 5 +++++
 .../share/classes/jdk/jfr/internal/PlatformRecorder.java | 6 +++---
 .../classes/jdk/jfr/internal/PlatformRecording.java      | 9 +++++++++
 .../share/classes/jdk/jfr/internal/dcmd/DCmdStart.java   | 9 +++++++--
 .../jdk/jfr/api/consumer/recordingstream/TestStop.java   | 1 +
 12 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp
index 125a56a11..e4f2471ed 100644
--- a/src/hotspot/share/compiler/compilerOracle.cpp
+++ b/src/hotspot/share/compiler/compilerOracle.cpp
@@ -443,6 +443,10 @@ bool CompilerOracle::should_inline(const methodHandle& method) {
   return (check_predicate(CompileCommand::Inline, method));
 }
 
+bool CompilerOracle::should_not_prediction(const methodHandle& method) {
+  return (check_predicate(CompileCommand::Dontprediction, method));
+}
+
 bool CompilerOracle::should_not_inline(const methodHandle& method) {
   return check_predicate(CompileCommand::DontInline, method) || check_predicate(CompileCommand::Exclude, method);
 }
diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp
index d7d9e15c5..48bc28ae0 100644
--- a/src/hotspot/share/compiler/compilerOracle.hpp
+++ b/src/hotspot/share/compiler/compilerOracle.hpp
@@ -51,6 +51,7 @@ class methodHandle;
   option(Print, "print", Bool) \
   option(Inline,  "inline", Bool) \
   option(DontInline,  "dontinline", Bool) \
+  option(Dontprediction,  "dontprediction", Bool) \
   option(Blackhole,  "blackhole", Bool) \
   option(CompileOnly, "compileonly", Bool)\
   option(Exclude, "exclude", Bool) \
@@ -157,6 +158,9 @@ class CompilerOracle : AllStatic {
   // A wrapper for checking bool options
   static bool has_option(const methodHandle& method, enum CompileCommand option);
 
+  // A wrapper for checking prediction option
+  static bool should_not_prediction(const methodHandle& method);
+
   // Check if method has option and value set. If yes, overwrite value and return true,
   // otherwise leave value unchanged and return false.
   template<typename T>
diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml
index 3045a46e1..9e6e68f6d 100644
--- a/src/hotspot/share/jfr/metadata/metadata.xml
+++ b/src/hotspot/share/jfr/metadata/metadata.xml
@@ -956,6 +956,7 @@
     <Field type="int" name="bailoutCount" label="Bailouts" />
     <Field type="int" name="invalidatedCount" label="Invalidated Compilations" />
     <Field type="int" name="osrCompileCount" label="OSR Compilations" />
+    <Field type="int" name="deoptimizationCount" label="Deoptimizations" />
     <Field type="int" name="standardCompileCount" label="Standard Compilations" />
     <Field type="ulong" contentType="bytes" name="osrBytesCompiled" label="OSR Bytes Compiled" />
     <Field type="ulong" contentType="bytes" name="standardBytesCompiled" label="Standard Bytes Compiled" />
diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
index 0582f91eb..5f2256542 100644
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
@@ -651,6 +651,9 @@ TRACE_REQUEST_FUNC(CompilerStatistics) {
   event.set_bailoutCount(CompileBroker::get_total_bailout_count());
   event.set_invalidatedCount(CompileBroker::get_total_invalidated_count());
   event.set_osrCompileCount(CompileBroker::get_total_osr_compile_count());
+#ifdef COMPILER2
+  event.set_deoptimizationCount(Deoptimization::total_deoptimization_count());
+#endif
   event.set_standardCompileCount(CompileBroker::get_total_standard_compile_count());
   event.set_osrBytesCompiled(CompileBroker::get_sum_osr_bytes_compiled());
   event.set_standardBytesCompiled(CompileBroker::get_sum_standard_bytes_compiled());
diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp
index 0307091fb..387b28420 100644
--- a/src/hotspot/share/opto/parse2.cpp
+++ b/src/hotspot/share/opto/parse2.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "ci/ciMethodData.hpp"
+#include "ci/ciUtilities.inline.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "compiler/compileLog.hpp"
 #include "interpreter/linkResolver.hpp"
@@ -1314,6 +1315,14 @@ float Parse::branch_prediction(float& cnt,
                                BoolTest::mask btest,
                                int target_bci,
                                Node* test) {
+  {
+    VM_ENTRY_MARK
+    methodHandle mh(THREAD, _method->get_Method());
+    if (CompilerOracle::should_not_prediction(mh)) {
+       return PROB_FAIR;
+    }
+  }
+
   float prob = dynamic_branch_prediction(cnt, btest, test);
   // If prob is unknown, switch to static prediction
   if (prob != PROB_UNKNOWN)  return prob;
diff --git a/src/hotspot/share/services/diagnosticArgument.cpp b/src/hotspot/share/services/diagnosticArgument.cpp
index 94f2d3e1e..033c73f91 100644
--- a/src/hotspot/share/services/diagnosticArgument.cpp
+++ b/src/hotspot/share/services/diagnosticArgument.cpp
@@ -215,6 +215,7 @@ template <> void DCmdArgument<NanoTimeArgument>::parse_value(const char* str,
               "Integer parsing error nanotime value: syntax error\n");
   }
   size_t idx = 0;
+  if (_value._time < 0) idx++;
   while(idx < len && isdigit(str[idx])) {
     idx++;
   }
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java
index 4409f51f4..4fb2be814 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java
@@ -610,6 +610,14 @@ public final class Recording implements Closeable {
         internal.setDuration(duration);
     }
 
+    public void setPreRecord(long pre) {
+        internal.setPreRecord(pre);
+    }
+
+    public long getPreRecord() {
+        return internal.getPreRecord();
+    }
+
     /**
      * Enables the event with the specified name.
      * <p>
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java
index cba39f0cd..210e901c8 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java
@@ -107,6 +107,7 @@ public final class RecordingStream implements AutoCloseable, EventStream {
         AccessControlContext acc = AccessController.getContext();
         this.recording = new Recording();
         this.creationTime = Instant.now();
+        this.recording.setPreRecord(-1);
         this.recording.setName("Recording Stream: " + creationTime);
         try {
             PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
@@ -239,6 +240,10 @@ public final class RecordingStream implements AutoCloseable, EventStream {
         return recording.disable(eventClass);
     }
 
+    public void setPreRecord(long pre) {
+        this.recording.setPreRecord(pre);
+    }
+
     /**
      * Determines how far back data is kept for the stream.
      * <p>
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
index 5933b9045..6e67eb7a2 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
@@ -254,7 +254,7 @@ public final class PlatformRecorder {
             }
             recording.setState(RecordingState.RUNNING);
             updateSettings(false);
-            recording.setStartTime(startTime);
+            recording.setStartTime(startTime.plusNanos(recording.getPreRecord()));
             writeMetaEvents();
             setRunPeriodicTask(true);
         } else {
@@ -271,12 +271,12 @@ public final class PlatformRecorder {
             }
             startNanos = Utils.getChunkStartNanos();
             startTime = Utils.epochNanosToInstant(startNanos);
-            recording.setStartTime(startTime);
+            recording.setStartTime(startTime.plusNanos(recording.getPreRecord()));
             recording.setState(RecordingState.RUNNING);
             updateSettings(false);
             writeMetaEvents();
             if (currentChunk != null) {
-                finishChunk(currentChunk, startTime, recording);
+                finishChunk(currentChunk, startTime, recording.getPreRecord() == 0 ? recording : null);
             }
             currentChunk = newChunk;
         }
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java
index 53c67b899..17cbebeef 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java
@@ -68,6 +68,7 @@ public final class PlatformRecording implements AutoCloseable {
     private Duration duration;
     private Duration maxAge;
     private long maxSize;
+    private long preRecord;
 
     private WriteableUserPath destination;
 
@@ -653,6 +654,14 @@ public final class PlatformRecording implements AutoCloseable {
         }
     }
 
+    public void setPreRecord(long pre) {
+        this.preRecord = pre;
+    }
+
+    public long getPreRecord() {
+        return preRecord;
+    }
+
     void updateTimer() {
         if (stopTask != null) {
             stopTask.cancel();
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java
index b40620e6d..fe29445fd 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java
@@ -117,7 +117,7 @@ final class DCmdStart extends AbstractDCmd {
         }
 
         if (delay != null) {
-            if (delay < 1000L * 1000L * 1000L) {
+            if (delay >= 0 && delay < 1000L * 1000L * 1000L) {
                 // to avoid typo, delay shorter than 1s makes no sense.
                 throw new DCmdException("Could not start recording, delay must be at least 1 second.");
             }
@@ -201,13 +201,18 @@ final class DCmdStart extends AbstractDCmd {
             recording.setDumpOnExit(dumpOnExit);
         }
 
-        if (delay != null) {
+        if (delay != null && delay >= 0) {
             Duration dDelay = Duration.ofNanos(delay);
             recording.scheduleStart(dDelay);
             print("Recording " + recording.getId() + " scheduled to start in ");
             printTimespan(dDelay, " ");
             print(".");
         } else {
+            if (delay != null && delay < 0) {
+                recording.setPreRecord(delay);
+            } else {
+                recording.setPreRecord(0);
+            }
             recording.start();
             print("Started recording " + recording.getId() + ".");
         }
diff --git a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestStop.java b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestStop.java
index 5cabd9e68..298026ec7 100644
--- a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestStop.java
+++ b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestStop.java
@@ -120,6 +120,7 @@ public class TestStop {
             try (RecordingStream inner = new RecordingStream()) {
                 inner.setMaxSize(100_000_000);
                 inner.onEvent(e -> innerCount.incrementAndGet());
+                inner.setPreRecord(0);
                 inner.startAsync();
 
                 MarkEvent b = new MarkEvent();
-- 
2.17.1