From 021fdc25f792b95cd21bef33183f4d0a062accb5 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 27 Sep 2024 23:11:44 +0200 Subject: [PATCH] Using tristate CompilerThread::_can_call_java. --- src/hotspot/share/compiler/compilerThread.cpp | 4 ++- src/hotspot/share/compiler/compilerThread.hpp | 5 ++-- src/hotspot/share/jvmci/jvmci.cpp | 18 ++++++----- src/hotspot/share/jvmci/jvmci.hpp | 26 +++++++++++----- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 30 ++++++++++++------- src/hotspot/share/jvmci/jvmciEnv.cpp | 2 +- .../CompilerThreadCanCallJavaScope.java | 9 +++--- .../jdk/vm/ci/hotspot/CompilerToVM.java | 10 ++++--- 8 files changed, 68 insertions(+), 36 deletions(-) diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index e212200a47c65..1c327a15ce090 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -56,7 +56,9 @@ CompilerThread::~CompilerThread() { void CompilerThread::set_compiler(AbstractCompiler* c) { // Only jvmci compiler threads can call Java - _can_call_java = c != nullptr && c->is_jvmci(); + if (c != nullptr && c->is_jvmci()) { + _can_call_java = TriBool{}; + } _compiler = c; } diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index 3531fb6d72ddf..fb59dd743ed35 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_COMPILER_COMPILERTHREAD_HPP #define SHARE_COMPILER_COMPILERTHREAD_HPP +#include #include "runtime/javaThread.hpp" class AbstractCompiler; @@ -50,7 +51,7 @@ class CompilerThread : public JavaThread { CompileTask* volatile _task; // print_threads_compiling can read this concurrently. CompileQueue* _queue; BufferBlob* _buffer_blob; - bool _can_call_java; + TriBool _can_call_java; AbstractCompiler* _compiler; TimeStamp _idle_time; @@ -73,7 +74,7 @@ class CompilerThread : public JavaThread { bool is_Compiler_thread() const { return true; } - virtual bool can_call_java() const { return _can_call_java; } + virtual bool can_call_java() const { return _can_call_java.is_default() || _can_call_java; } // Returns true if this CompilerThread is hidden from JVMTI and FlightRecorder. C1 and C2 are // always hidden but JVMCI compiler threads might be hidden. diff --git a/src/hotspot/share/jvmci/jvmci.cpp b/src/hotspot/share/jvmci/jvmci.cpp index f8a55f27614df..162f442e3689d 100644 --- a/src/hotspot/share/jvmci/jvmci.cpp +++ b/src/hotspot/share/jvmci/jvmci.cpp @@ -54,29 +54,33 @@ volatile intx JVMCI::_fatal_log_init_thread = -1; volatile int JVMCI::_fatal_log_fd = -1; const char* JVMCI::_fatal_log_filename = nullptr; -CompilerThread* CompilerThreadCanCallJava::update(JavaThread* current, bool new_state) { +Pair CompilerThreadCanCallJava::update(JavaThread* current, const TriBool new_state, bool force) { if (current->is_Compiler_thread()) { CompilerThread* ct = CompilerThread::cast(current); if (ct->_can_call_java != new_state && + (force || ct->_can_call_java.is_default()) && ct->_compiler != nullptr && ct->_compiler->is_jvmci()) { // Only update the state if the ability of the // current thread to call Java actually changes + TriBool prev_state{ct->_can_call_java}; ct->_can_call_java = new_state; - return ct; + return {ct, prev_state}; } } - return nullptr; + return {nullptr, {}}; } -CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) { - _current = CompilerThreadCanCallJava::update(current, new_state); +CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state, bool force) { + Pair p = CompilerThreadCanCallJava::update(current, new_state, force); + _current = p.first; + _prev_can_call_java = p.second; } CompilerThreadCanCallJava::~CompilerThreadCanCallJava() { if (_current != nullptr) { - _current->_can_call_java = !_current->_can_call_java; + _current->_can_call_java = _prev_can_call_java; } } @@ -205,7 +209,7 @@ void JVMCI::ensure_box_caches_initialized(TRAPS) { // Class resolution and initialization below // requires calling into Java - CompilerThreadCanCallJava ccj(THREAD, true); + CompilerThreadCanCallJava ccj(THREAD, true, true); for (unsigned i = 0; i < sizeof(box_classes) / sizeof(Symbol*); i++) { Klass* k = SystemDictionary::resolve_or_fail(box_classes[i], true, CHECK); diff --git a/src/hotspot/share/jvmci/jvmci.hpp b/src/hotspot/share/jvmci/jvmci.hpp index dd679692ff593..99836c0e89dc7 100644 --- a/src/hotspot/share/jvmci/jvmci.hpp +++ b/src/hotspot/share/jvmci/jvmci.hpp @@ -24,6 +24,8 @@ #ifndef SHARE_JVMCI_JVMCI_HPP #define SHARE_JVMCI_JVMCI_HPP +#include +#include #include "compiler/compiler_globals.hpp" #include "compiler/compilerDefinitions.hpp" #include "utilities/exceptions.hpp" @@ -60,14 +62,24 @@ typedef struct _jmetadata *jmetadata; class CompilerThreadCanCallJava : StackObj { private: CompilerThread* _current; // Only non-null if state of thread changed + TriBool _prev_can_call_java; public: - // If the current thread is a CompilerThread associated with - // a JVMCI compiler where CompilerThread::_can_call_java != new_state, - // then _can_call_java is set to `new_state` - // Returns nullptr if no change was made, otherwise the current CompilerThread - static CompilerThread* update(JavaThread* current, bool new_state); - - CompilerThreadCanCallJava(JavaThread* current, bool new_state); + // Updates the `_can_call_java` state for the current thread if it's a `CompilerThread` + // associated with a JVMCI compiler. + // + // Conditions for updating: + // - The current thread must be a `CompilerThread`. + // - The thread's `_can_call_java` field must not already match `new_state`. + // - Either the `force` flag must be `true`, or `_can_call_java` must be a default `TriBool` value. + // - The thread must be associated with a valid JVMCI compiler (`_compiler != nullptr` and `_compiler->is_jvmci()`). + // + // If the update is performed, `_can_call_java` is set to `new_state`, and the method returns a + // `Pair` containing the current `CompilerThread` and its previous `_can_call_java` value. + // + // If no update is performed, the method returns a `Pair` with `nullptr` and a default `TriBool` value. + static Pair update(JavaThread* current, TriBool new_state, bool force); + + CompilerThreadCanCallJava(JavaThread* current, bool new_state, bool force=false); // Resets CompilerThread::_can_call_java of the current thread if the // constructor changed it. diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 4790f29ef497a..b1b330699e965 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -401,8 +401,18 @@ C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject e return JVMCIENV->get_jobject(result); } -C2V_VMENTRY_0(jboolean, updateCompilerThreadCanCallJava, (JNIEnv* env, jobject, jboolean newState)) - return CompilerThreadCanCallJava::update(THREAD, newState) != nullptr; +C2V_VMENTRY_PREFIX(jint, updateCompilerThreadCanCallJava, (JNIEnv* env, jobject, jint newState)) + TriBool new_state{}; + if (newState != -1) { + new_state = static_cast(newState); + } + Pair p = CompilerThreadCanCallJava::update(thread, new_state, true); + TriBool result = p.first == nullptr ? new_state : p.second; + if (result.is_default()) { + return -1; + } else { + return static_cast(p.second); + } C2V_END @@ -588,7 +598,7 @@ C2V_VMENTRY_0(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, ARGUMENT_PAIR( C2V_END C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGUMENT_PAIR(accessing_klass), jint accessing_klass_loader, jboolean resolve)) - CompilerThreadCanCallJava canCallJava(thread, resolve); // Resolution requires Java calls + CompilerThreadCanCallJava canCallJava(thread, resolve, true); // Resolution requires Java calls JVMCIObject name = JVMCIENV->wrap(jname); const char* str = JVMCIENV->as_utf8_string(name); TempNewSymbol class_name = SymbolTable::new_symbol(str); @@ -2036,7 +2046,7 @@ C2V_VMENTRY(void, ensureInitialized, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass) C2V_END C2V_VMENTRY(void, ensureLinked, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) - CompilerThreadCanCallJava canCallJava(thread, true); // Linking requires Java calls + CompilerThreadCanCallJava canCallJava(thread, true, true); // Linking requires Java calls Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { JVMCI_THROW(NullPointerException); @@ -2802,7 +2812,7 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool return 0L; } PEER_JVMCIENV_FROM_THREAD(THREAD, !JVMCIENV->is_hotspot()); - CompilerThreadCanCallJava canCallJava(thread, PEER_JVMCIENV->is_hotspot()); + CompilerThreadCanCallJava canCallJava(thread, PEER_JVMCIENV->is_hotspot(), true); PEER_JVMCIENV->check_init(JVMCI_CHECK_0); JVMCIEnv* thisEnv = JVMCIENV; @@ -3025,21 +3035,21 @@ static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationA C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jobject filter, jint filter_length, jlong filter_klass_pointers)) - CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support + CompilerThreadCanCallJava canCallJava(thread, true, true); // Requires Java support InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); return get_encoded_annotation_data(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jobject filter, jint filter_length, jlong filter_klass_pointers)) - CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support + CompilerThreadCanCallJava canCallJava(thread, true, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); return get_encoded_annotation_data(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jobject filter, jint filter_length, jlong filter_klass_pointers)) - CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support + CompilerThreadCanCallJava canCallJava(thread, true, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCIENV); fieldDescriptor fd(holder, index); return get_encoded_annotation_data(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); @@ -3103,7 +3113,7 @@ C2V_VMENTRY(void, callSystemExit, (JNIEnv* env, jobject, jint status)) vm_exit_during_initialization(); } } - CompilerThreadCanCallJava canCallJava(thread, true); + CompilerThreadCanCallJava canCallJava(thread, true, true); JavaValue result(T_VOID); JavaCallArguments jargs(1); jargs.push_int(status); @@ -3392,7 +3402,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, - {CC "updateCompilerThreadCanCallJava", CC "(Z)Z", FN_PTR(updateCompilerThreadCanCallJava)}, + {CC "updateCompilerThreadCanCallJava", CC "(I)I", FN_PTR(updateCompilerThreadCanCallJava)}, }; int CompilerToVM::methods_count() { diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 129a88ac4d7fb..ea64790148cf9 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1372,7 +1372,7 @@ JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS) JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. jboolean exception = false; if (is_hotspot()) { - CompilerThreadCanCallJava ccj(THREAD, true); + CompilerThreadCanCallJava ccj(THREAD, true, true); JavaValue result(T_OBJECT); JavaCallArguments args; args.push_long(pointer); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java index ff346fa94bcd8..a53abd8a82571 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java @@ -35,7 +35,7 @@ public class CompilerThreadCanCallJavaScope implements AutoCloseable { /** * Thread state used during the scope. */ - private final boolean state; + private final int rawPrevState; /** * Non-null iff the thread state needs resetting in {@link #close()}. @@ -55,10 +55,11 @@ public class CompilerThreadCanCallJavaScope implements AutoCloseable { * @param newState true/false to allow/disallow VM-to-Java calls within the scope */ public CompilerThreadCanCallJavaScope(boolean newState) { - this.state = newState; this.thread = Thread.currentThread(); CompilerToVM vm = HotSpotJVMCIRuntime.runtime().getCompilerToVM(); - if (vm.updateCompilerThreadCanCallJava(newState)) { + int rawNewState = newState ? 1 : 0; + this.rawPrevState = vm.updateCompilerThreadCanCallJava(rawNewState); + if (rawPrevState != rawNewState) { this.vm = vm; } else { this.vm = null; @@ -78,7 +79,7 @@ public void close() { } if (vm != null) { - vm.updateCompilerThreadCanCallJava(!state); + vm.updateCompilerThreadCanCallJava(rawPrevState); } } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 12c6dfd3f9dcd..6fcfb56f28a2f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1516,10 +1516,12 @@ void getOopMapAt(HotSpotResolvedJavaMethodImpl method, int bci, long[] oopMap) { native void getOopMapAt(HotSpotResolvedJavaMethodImpl method, long methodPointer, int bci, long[] oopMap); /** - * If the current thread is a CompilerThread associated with a JVMCI compiler where - * newState != CompilerThread::_can_call_java, then _can_call_java is set to newState. + * If the current thread is a {@code CompilerThread} associated with a JVMCI compiler where + * {@code newState != CompilerThread::_can_call_java}, then {@code _can_call_java} is set + * to {@code newState}. * - * @returns false if no change was made, otherwise true + * @return the previous {@code _can_call_java} value if change was made, + * otherwise {@code newState} */ - native boolean updateCompilerThreadCanCallJava(boolean newState); + native int updateCompilerThreadCanCallJava(int newState); }