From cc3ead24e106b94f5150b8ea4088dea405636aa5 Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Tue, 7 Jan 2025 19:21:57 +0400 Subject: [PATCH] JBR-7457 Provide JBR API method to explicitly call gc() --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 7 +++++++ src/hotspot/share/gc/g1/g1VMOperations.cpp | 9 +++++++-- src/hotspot/share/gc/serial/serialHeap.cpp | 4 +++- src/hotspot/share/gc/shared/gcCause.cpp | 3 +++ src/hotspot/share/gc/shared/gcCause.hpp | 4 +++- src/hotspot/share/gc/z/zCollectedHeap.cpp | 1 + src/hotspot/share/gc/z/zDriver.cpp | 3 +++ src/hotspot/share/prims/jni.cpp | 4 ++++ src/hotspot/share/prims/jniCheck.cpp | 6 ++++++ .../share/classes/java/lang/Exception.java | 1 + src/java.base/share/classes/java/lang/System.java | 4 ++++ src/java.base/share/native/libjava/System.c | 13 +++++++++++++ .../classes/sun/jvm/hotspot/gc/shared/GCCause.java | 1 + 13 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index a63123e1d6ff..6620e652f5c1 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1849,6 +1849,13 @@ bool G1CollectedHeap::try_collect_fullgc(GCCause::Cause cause, const G1GCCounters& counters_before) { assert_heap_not_locked(); + if (cause == GCCause::_jbr_gc_run) { + VM_G1CollectForAllocation op(0, // no following allocation + counters_before.total_collections(), + cause); + VMThread::execute(&op); + } + while(true) { VM_G1CollectFull op(counters_before.total_collections(), counters_before.total_full_collections(), diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 634cdf6265fd..2f2171bb2b81 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -51,8 +51,13 @@ bool VM_G1CollectFull::skip_operation() const { void VM_G1CollectFull::doit() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); GCCauseSetter x(g1h, _gc_cause); - _gc_succeeded = g1h->do_full_collection(false /* clear_all_soft_refs */, - false /* do_maximal_compaction */); + if (_gc_cause == GCCause::_jbr_gc_run) { + _gc_succeeded = g1h->do_full_collection(true /* clear_all_soft_refs */, + true /* do_maximal_compaction */); + } else { + _gc_succeeded = g1h->do_full_collection(false /* clear_all_soft_refs */, + false /* do_maximal_compaction */); + } } VM_G1TryInitiateConcMark::VM_G1TryInitiateConcMark(uint gc_count_before, diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 9efa207ca97d..3df233fe1180 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -22,6 +22,7 @@ * */ +#include "gc/shared/gcCause.hpp" #include "precompiled.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" @@ -431,7 +432,8 @@ HeapWord* SerialHeap::mem_allocate(size_t size, bool SerialHeap::must_clear_all_soft_refs() { return _gc_cause == GCCause::_metadata_GC_clear_soft_refs || - _gc_cause == GCCause::_wb_full_gc; + _gc_cause == GCCause::_wb_full_gc || + _gc_cause == GCCause::_jbr_gc_run; } bool SerialHeap::is_young_gc_safe() const { diff --git a/src/hotspot/share/gc/shared/gcCause.cpp b/src/hotspot/share/gc/shared/gcCause.cpp index f73d3146aa3c..a9fcd55c55d8 100644 --- a/src/hotspot/share/gc/shared/gcCause.cpp +++ b/src/hotspot/share/gc/shared/gcCause.cpp @@ -126,6 +126,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _last_gc_cause: return "ILLEGAL VALUE - last gc cause - ILLEGAL VALUE"; + case _jbr_gc_run: + return "JBR full GC"; + default: return "unknown GCCause"; } diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index 347e32be86a3..26976fe064b1 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -72,6 +72,7 @@ class GCCause : public AllStatic { _g1_periodic_collection, _dcmd_gc_run, + _jbr_gc_run, _shenandoah_stop_vm, _shenandoah_allocation_failure_evac, @@ -90,7 +91,8 @@ class GCCause : public AllStatic { inline static bool is_user_requested_gc(GCCause::Cause cause) { return (cause == GCCause::_java_lang_system_gc || - cause == GCCause::_dcmd_gc_run); + cause == GCCause::_dcmd_gc_run || + cause == GCCause::_jbr_gc_run); } inline static bool is_explicit_full_gc(GCCause::Cause cause) { diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index d9ec2d8c6077..b858a3e6d85b 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -191,6 +191,7 @@ void ZCollectedHeap::collect(GCCause::Cause cause) { case GCCause::_wb_full_gc: case GCCause::_wb_breakpoint: case GCCause::_dcmd_gc_run: + case GCCause::_jbr_gc_run: case GCCause::_java_lang_system_gc: case GCCause::_full_gc_alot: case GCCause::_jvmti_force_gc: diff --git a/src/hotspot/share/gc/z/zDriver.cpp b/src/hotspot/share/gc/z/zDriver.cpp index c91de172fee4..deeb7bc0880c 100644 --- a/src/hotspot/share/gc/z/zDriver.cpp +++ b/src/hotspot/share/gc/z/zDriver.cpp @@ -236,6 +236,7 @@ static bool should_clear_all_soft_references(GCCause::Cause cause) { case GCCause::_wb_full_gc: case GCCause::_metadata_GC_clear_soft_refs: case GCCause::_z_allocation_stall: + case GCCause::_jbr_gc_run: return true; case GCCause::_heap_dump: @@ -276,6 +277,7 @@ static bool should_preclean_young(GCCause::Cause cause) { case GCCause::_wb_full_gc: case GCCause::_wb_breakpoint: case GCCause::_dcmd_gc_run: + case GCCause::_jbr_gc_run: case GCCause::_java_lang_system_gc: case GCCause::_full_gc_alot: case GCCause::_jvmti_force_gc: @@ -338,6 +340,7 @@ void ZDriverMajor::collect(const ZDriverRequest& request) { case GCCause::_heap_inspection: case GCCause::_wb_full_gc: case GCCause::_dcmd_gc_run: + case GCCause::_jbr_gc_run: case GCCause::_java_lang_system_gc: case GCCause::_full_gc_alot: case GCCause::_jvmti_force_gc: diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 380d46113c3c..e038429cb404 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -540,7 +540,11 @@ JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message)) } else if (name->equals("java/lang/Exception$JB$$Event")) { Events::log(THREAD, "%s", message); return 0; + } else if (name->equals("java/lang/Exception$JB$$FullGC")) { + Universe::heap()->collect(GCCause::_jbr_gc_run); + return 0; } + Handle class_loader (THREAD, k->class_loader()); THROW_MSG_LOADER_(name, (char *)message, class_loader, JNI_OK); ShouldNotReachHere(); diff --git a/src/hotspot/share/prims/jniCheck.cpp b/src/hotspot/share/prims/jniCheck.cpp index 8c1f9f53b343..fdb121dec8a1 100644 --- a/src/hotspot/share/prims/jniCheck.cpp +++ b/src/hotspot/share/prims/jniCheck.cpp @@ -505,6 +505,12 @@ void jniCheck::validate_throwable_klass(JavaThread* thr, Klass* klass) { ASSERT_OOPS_ALLOWED; assert(klass != nullptr, "klass argument must have a value"); + if (klass->name()->index_of_at(0, "/Exception$JB$$", strlen("/Exception$JB$$")) > 0) { + // This is a special "marker" class that is never really thrown and + // therefore it does not have to be Throwable. + return; + } + if (!klass->is_instance_klass() || !klass->is_subclass_of(vmClasses::Throwable_klass())) { ReportJNIFatalError(thr, fatal_class_not_a_throwable_class); diff --git a/src/java.base/share/classes/java/lang/Exception.java b/src/java.base/share/classes/java/lang/Exception.java index 0f36e2edd81c..7f228707e523 100644 --- a/src/java.base/share/classes/java/lang/Exception.java +++ b/src/java.base/share/classes/java/lang/Exception.java @@ -125,4 +125,5 @@ protected Exception(String message, Throwable cause, private static class JB$$Assertion {} private static class JB$$Event {} + private static class JB$$FullGC {} } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 2c9548d2bf98..83fe1294d5c7 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -61,6 +61,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import com.jetbrains.exported.JBRApi; import jdk.internal.javac.Restricted; import jdk.internal.loader.NativeLibraries; import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; @@ -2339,4 +2340,7 @@ public boolean bytesCompatible(String string, Charset charset) { } }); } + + @JBRApi.Provides("SystemUtils#fullGC") + private static native void $$jb$FullGC(); } diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index 7b038a6a9d59..b8bf869ef7bc 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -322,3 +322,16 @@ Java_java_lang_System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname) return (*env)->NewString(env, chars, len); } + +JNIEXPORT void JNICALL +Java_java_lang_System__00024_00024jb_00024FullGC(JNIEnv *env, jclass ign) +{ + jclass cls = (*env)->FindClass(env, "java/lang/Exception$JB$$FullGC"); + if (cls != 0) { + // Throwing an exception by this name will trigger a full GC with + // a special cause indicating the need to collect as much as possible + // for testing purposes. + (*env)->ThrowNew(env, cls, NULL); + } +} + diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java index b301f7743906..8e8c31072d78 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java @@ -54,6 +54,7 @@ public enum GCCause { _g1_periodic_collection ("G1 Periodic Collection"), _dcmd_gc_run ("Diagnostic Command"), + _jbr_gc_run("JBR full GC"), _shenandoah_allocation_failure_evac ("Allocation Failure During Evacuation"), _shenandoah_stop_vm ("Stopping VM"),