From 751a914b0a377d4e1dd30d2501f0ab4e327dea34 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 1 Nov 2024 13:36:26 +0000 Subject: [PATCH] 8340733: Add scope for relaxing constraint on JavaCalls from CompilerThread Reviewed-by: dnsimon, kvn --- src/hotspot/share/compiler/compilerThread.cpp | 7 +- src/hotspot/share/jvmci/jvmci.cpp | 15 ++-- src/hotspot/share/jvmci/jvmci.hpp | 13 ++- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 9 +- .../CompilerThreadCanCallJavaScope.java | 84 +++++++++++++++++++ .../jdk/vm/ci/hotspot/CompilerToVM.java | 8 ++ 6 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index e212200a47c..e6329f3e655 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -55,8 +55,11 @@ CompilerThread::~CompilerThread() { } void CompilerThread::set_compiler(AbstractCompiler* c) { - // Only jvmci compiler threads can call Java - _can_call_java = c != nullptr && c->is_jvmci(); + /* + * Compiler threads need to make Java upcalls to the jargraal compiler. + * Java upcalls are also needed by the InterpreterRuntime when using jargraal. + */ + _can_call_java = c != nullptr && c->is_jvmci() JVMCI_ONLY(&& !UseJVMCINativeLibrary); _compiler = c; } diff --git a/src/hotspot/share/jvmci/jvmci.cpp b/src/hotspot/share/jvmci/jvmci.cpp index 48d286e91ed..6d240bc9063 100644 --- a/src/hotspot/share/jvmci/jvmci.cpp +++ b/src/hotspot/share/jvmci/jvmci.cpp @@ -54,26 +54,29 @@ volatile intx JVMCI::_first_error_tid = -1; volatile int JVMCI::_fatal_log_fd = -1; const char* JVMCI::_fatal_log_filename = nullptr; -CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) { - _current = nullptr; +CompilerThread* CompilerThreadCanCallJava::update(JavaThread* current, bool new_state) { if (current->is_Compiler_thread()) { CompilerThread* ct = CompilerThread::cast(current); if (ct->_can_call_java != new_state && ct->_compiler != nullptr && ct->_compiler->is_jvmci()) { - // Only enter a new context if the ability of the + // Only update the state if the ability of the // current thread to call Java actually changes - _reset_state = ct->_can_call_java; ct->_can_call_java = new_state; - _current = ct; + return ct; } } + return nullptr; +} + +CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) { + _current = CompilerThreadCanCallJava::update(current, new_state); } CompilerThreadCanCallJava::~CompilerThreadCanCallJava() { if (_current != nullptr) { - _current->_can_call_java = _reset_state; + _current->_can_call_java = !_current->_can_call_java; } } diff --git a/src/hotspot/share/jvmci/jvmci.hpp b/src/hotspot/share/jvmci/jvmci.hpp index 4c1d828004e..49240174967 100644 --- a/src/hotspot/share/jvmci/jvmci.hpp +++ b/src/hotspot/share/jvmci/jvmci.hpp @@ -60,14 +60,13 @@ typedef struct _jmetadata *jmetadata; class CompilerThreadCanCallJava : StackObj { private: CompilerThread* _current; // Only non-null if state of thread changed - bool _reset_state; // Value prior to state change, undefined - // if no state change. public: - // Enters a scope in which the ability of the current CompilerThread - // to call Java is specified by `new_state`. This call only makes a - // change if the current thread is a CompilerThread associated with - // a JVMCI compiler whose CompilerThread::_can_call_java is not - // currently `new_state`. + // 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); // Resets CompilerThread::_can_call_java of the current thread if the diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index ba1155e6694..7922a681639 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -184,7 +184,8 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) { JVMCI_VM_ENTRY_MARK; \ ResourceMark rm; \ bool __is_hotspot = env == thread->jni_environment(); \ - CompilerThreadCanCallJava ccj(thread, __is_hotspot); \ + bool __block_can_call_java = __is_hotspot || !thread->is_Compiler_thread() || CompilerThread::cast(thread)->can_call_java(); \ + CompilerThreadCanCallJava ccj(thread, __block_can_call_java); \ JVMCIENV_FROM_JNI(JVMCI::compilation_tick(thread), env); \ // Entry to native method implementation that transitions @@ -401,6 +402,11 @@ C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject e return JVMCIENV->get_jobject(result); } +C2V_VMENTRY_PREFIX(jboolean, updateCompilerThreadCanCallJava, (JNIEnv* env, jobject, jboolean newState)) + return CompilerThreadCanCallJava::update(thread, newState) != nullptr; +C2V_END + + C2V_VMENTRY_NULL(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset)) Method* method = nullptr; JVMCIObject base_object = JVMCIENV->wrap(base); @@ -3386,6 +3392,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)}, }; int CompilerToVM::methods_count() { 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 new file mode 100644 index 00000000000..ff346fa94bc --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerThreadCanCallJavaScope.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * Scope used to potentially change whether the current thread can make VM-to-Java calls. + * A scope is exited by the {@link #close()} method so it should be used in a + * try-with-resources statement. + * + * The scope does nothing if the current thread is not a HotSpot VM CompilerThread + * for a JVMCI compiler. + */ +public class CompilerThreadCanCallJavaScope implements AutoCloseable { + + /** + * Thread state used during the scope. + */ + private final boolean state; + + /** + * Non-null iff the thread state needs resetting in {@link #close()}. + */ + private final CompilerToVM vm; + + /** + * The thread on which the constructor was called. + */ + private final Thread thread; + + /** + * Opens a scope to allow/disallow the current thread to make VM-to-Java calls. + * The scope is a no-op if the current thread is not a HotSpot VM CompilerThread + * for a JVMCI compiler. + * + * @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)) { + this.vm = vm; + } else { + this.vm = null; + } + } + + /** + * Resets the state of the current thread with respect to whether it can make + * VM-to-Java calls to what it was before the constructor was called. + * + * @throws IllegalStateException if called on a different thread than the constructor + */ + @Override + public void close() { + if (this.thread != Thread.currentThread()) { + throw new IllegalStateException(); + } + + if (vm != null) { + vm.updateCompilerThreadCanCallJava(!state); + } + } +} 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 59369754526..12c6dfd3f9d 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 @@ -1514,4 +1514,12 @@ final class CompilerToVM { } 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. + * + * @returns false if no change was made, otherwise true + */ + native boolean updateCompilerThreadCanCallJava(boolean newState); }