Skip to content

Commit d354141

Browse files
author
Doug Simon
committed
8318694: [JVMCI] disable can_call_java in most contexts for libjvmci compiler threads
Reviewed-by: dholmes, never
1 parent c86592d commit d354141

File tree

13 files changed

+132
-88
lines changed

13 files changed

+132
-88
lines changed

src/hotspot/share/classfile/javaClasses.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2453,7 +2453,7 @@ void java_lang_Throwable::print_stack_trace(Handle throwable, outputStream* st)
24532453
BacktraceElement bte = iter.next(THREAD);
24542454
print_stack_element_to_stream(st, bte._mirror, bte._method_id, bte._version, bte._bci, bte._name);
24552455
}
2456-
{
2456+
if (THREAD->can_call_java()) {
24572457
// Call getCause() which doesn't necessarily return the _cause field.
24582458
ExceptionMark em(THREAD);
24592459
JavaValue cause(T_OBJECT);
@@ -2475,6 +2475,9 @@ void java_lang_Throwable::print_stack_trace(Handle throwable, outputStream* st)
24752475
st->cr();
24762476
}
24772477
}
2478+
} else {
2479+
st->print_raw_cr("<<cannot call Java to get cause>>");
2480+
return;
24782481
}
24792482
}
24802483
}

src/hotspot/share/classfile/systemDictionary.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
611611
InstanceKlass* loaded_class = nullptr;
612612
SymbolHandle superclassname; // Keep alive while loading in parallel thread.
613613

614-
assert(THREAD->can_call_java(),
614+
guarantee(THREAD->can_call_java(),
615615
"can not load classes with compiler thread: class=%s, classloader=%s",
616616
name->as_C_string(),
617617
class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string());
@@ -2056,7 +2056,7 @@ Method* SystemDictionary::find_method_handle_invoker(Klass* klass,
20562056
Klass* accessing_klass,
20572057
Handle* appendix_result,
20582058
TRAPS) {
2059-
assert(THREAD->can_call_java() ,"");
2059+
guarantee(THREAD->can_call_java(), "");
20602060
Handle method_type =
20612061
SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_NULL);
20622062

src/hotspot/share/compiler/compilerThread.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ CompilerThread::CompilerThread(CompileQueue* queue,
3939
_queue = queue;
4040
_counters = counters;
4141
_buffer_blob = nullptr;
42+
_can_call_java = false;
4243
_compiler = nullptr;
4344
_arena_stat = CompilationMemoryStatistic::enabled() ? new ArenaStatCounter : nullptr;
4445

@@ -56,15 +57,17 @@ CompilerThread::~CompilerThread() {
5657
delete _arena_stat;
5758
}
5859

60+
void CompilerThread::set_compiler(AbstractCompiler* c) {
61+
// Only jvmci compiler threads can call Java
62+
_can_call_java = c != nullptr && c->is_jvmci();
63+
_compiler = c;
64+
}
65+
5966
void CompilerThread::thread_entry(JavaThread* thread, TRAPS) {
6067
assert(thread->is_Compiler_thread(), "must be compiler thread");
6168
CompileBroker::compiler_thread_loop();
6269
}
6370

64-
bool CompilerThread::can_call_java() const {
65-
return _compiler != nullptr && _compiler->is_jvmci();
66-
}
67-
6871
// Hide native compiler threads from external view.
6972
bool CompilerThread::is_hidden_from_external_view() const {
7073
return _compiler == nullptr || _compiler->is_hidden_from_external_view();

src/hotspot/share/compiler/compilerThread.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,17 @@ class AbstractCompiler;
3131
class ArenaStatCounter;
3232
class BufferBlob;
3333
class ciEnv;
34-
class CompileThread;
34+
class CompilerThread;
3535
class CompileLog;
3636
class CompileTask;
3737
class CompileQueue;
3838
class CompilerCounters;
3939
class IdealGraphPrinter;
40-
class JVMCIEnv;
41-
class JVMCIPrimitiveArray;
4240

4341
// A thread used for Compilation.
4442
class CompilerThread : public JavaThread {
4543
friend class VMStructs;
44+
JVMCI_ONLY(friend class CompilerThreadCanCallJava;)
4645
private:
4746
CompilerCounters* _counters;
4847

@@ -51,6 +50,7 @@ class CompilerThread : public JavaThread {
5150
CompileTask* volatile _task; // print_threads_compiling can read this concurrently.
5251
CompileQueue* _queue;
5352
BufferBlob* _buffer_blob;
53+
bool _can_call_java;
5454

5555
AbstractCompiler* _compiler;
5656
TimeStamp _idle_time;
@@ -73,13 +73,13 @@ class CompilerThread : public JavaThread {
7373

7474
bool is_Compiler_thread() const { return true; }
7575

76-
virtual bool can_call_java() const;
76+
virtual bool can_call_java() const { return _can_call_java; }
7777

7878
// Returns true if this CompilerThread is hidden from JVMTI and FlightRecorder. C1 and C2 are
7979
// always hidden but JVMCI compiler threads might be hidden.
8080
virtual bool is_hidden_from_external_view() const;
8181

82-
void set_compiler(AbstractCompiler* c) { _compiler = c; }
82+
void set_compiler(AbstractCompiler* c);
8383
AbstractCompiler* compiler() const { return _compiler; }
8484

8585
CompileQueue* queue() const { return _queue; }

src/hotspot/share/jvmci/jvmci.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include "precompiled.hpp"
2525
#include "classfile/systemDictionary.hpp"
26+
#include "compiler/abstractCompiler.hpp"
2627
#include "compiler/compileTask.hpp"
2728
#include "compiler/compilerThread.hpp"
2829
#include "gc/shared/collectedHeap.hpp"
@@ -53,6 +54,29 @@ volatile intx JVMCI::_fatal_log_init_thread = -1;
5354
volatile int JVMCI::_fatal_log_fd = -1;
5455
const char* JVMCI::_fatal_log_filename = nullptr;
5556

57+
CompilerThreadCanCallJava::CompilerThreadCanCallJava(JavaThread* current, bool new_state) {
58+
_current = nullptr;
59+
if (current->is_Compiler_thread()) {
60+
CompilerThread* ct = CompilerThread::cast(current);
61+
if (ct->_can_call_java != new_state &&
62+
ct->_compiler != nullptr &&
63+
ct->_compiler->is_jvmci())
64+
{
65+
// Only enter a new context if the ability of the
66+
// current thread to call Java actually changes
67+
_reset_state = ct->_can_call_java;
68+
ct->_can_call_java = new_state;
69+
_current = ct;
70+
}
71+
}
72+
}
73+
74+
CompilerThreadCanCallJava::~CompilerThreadCanCallJava() {
75+
if (_current != nullptr) {
76+
_current->_can_call_java = _reset_state;
77+
}
78+
}
79+
5680
void jvmci_vmStructs_init() NOT_DEBUG_RETURN;
5781

5882
bool JVMCI::can_initialize_JVMCI() {
@@ -176,6 +200,10 @@ void JVMCI::ensure_box_caches_initialized(TRAPS) {
176200
java_lang_Long_LongCache::symbol()
177201
};
178202

203+
// Class resolution and initialization below
204+
// requires calling into Java
205+
CompilerThreadCanCallJava ccj(THREAD, true);
206+
179207
for (unsigned i = 0; i < sizeof(box_classes) / sizeof(Symbol*); i++) {
180208
Klass* k = SystemDictionary::resolve_or_fail(box_classes[i], true, CHECK);
181209
InstanceKlass* ik = InstanceKlass::cast(k);

src/hotspot/share/jvmci/jvmci.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "utilities/exceptions.hpp"
3030

3131
class BoolObjectClosure;
32+
class CompilerThread;
3233
class constantPoolHandle;
3334
class JavaThread;
3435
class JVMCIEnv;
@@ -46,6 +47,34 @@ typedef FormatStringEventLog<256> StringEventLog;
4647
struct _jmetadata;
4748
typedef struct _jmetadata *jmetadata;
4849

50+
// A stack object that manages a scope in which the current thread, if
51+
// it's a CompilerThread, can have its CompilerThread::_can_call_java
52+
// field changed. This allows restricting libjvmci better in terms
53+
// of when it can make Java calls. If a Java call on a CompilerThread
54+
// reaches a clinit, there's a risk of dead-lock when async compilation
55+
// is disabled (e.g. -Xbatch or -Xcomp) as the non-CompilerThread thread
56+
// waiting for the blocking compilation may hold the clinit lock.
57+
//
58+
// This scope is primarily used to disable Java calls when libjvmci enters
59+
// the VM via a C2V (i.e. CompilerToVM) native method.
60+
class CompilerThreadCanCallJava : StackObj {
61+
private:
62+
CompilerThread* _current; // Only non-null if state of thread changed
63+
bool _reset_state; // Value prior to state change, undefined
64+
// if no state change.
65+
public:
66+
// Enters a scope in which the ability of the current CompilerThread
67+
// to call Java is specified by `new_state`. This call only makes a
68+
// change if the current thread is a CompilerThread associated with
69+
// a JVMCI compiler whose CompilerThread::_can_call_java is not
70+
// currently `new_state`.
71+
CompilerThreadCanCallJava(JavaThread* current, bool new_state);
72+
73+
// Resets CompilerThread::_can_call_java of the current thread if the
74+
// constructor changed it.
75+
~CompilerThreadCanCallJava();
76+
};
77+
4978
class JVMCI : public AllStatic {
5079
friend class JVMCIRuntime;
5180
friend class JVMCIEnv;

src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,19 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) {
165165
MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \
166166
ThreadInVMfromNative __tiv(thread); \
167167
HandleMarkCleaner __hm(thread); \
168-
JavaThread* THREAD = thread; \
168+
JavaThread* THREAD = thread; \
169169
debug_only(VMNativeEntryWrapper __vew;)
170170

171171
// Native method block that transitions current thread to '_thread_in_vm'.
172-
#define C2V_BLOCK(result_type, name, signature) \
173-
JVMCI_VM_ENTRY_MARK; \
174-
ResourceMark rm; \
175-
JVMCIENV_FROM_JNI(JVMCI::compilation_tick(thread), env);
172+
// Note: CompilerThreadCanCallJava must precede JVMCIENV_FROM_JNI so that
173+
// the translation of an uncaught exception in the JVMCIEnv does not make
174+
// a Java call when __is_hotspot == false.
175+
#define C2V_BLOCK(result_type, name, signature) \
176+
JVMCI_VM_ENTRY_MARK; \
177+
ResourceMark rm; \
178+
bool __is_hotspot = env == thread->jni_environment(); \
179+
CompilerThreadCanCallJava ccj(thread, __is_hotspot); \
180+
JVMCIENV_FROM_JNI(JVMCI::compilation_tick(thread), env); \
176181

177182
static JavaThread* get_current_thread(bool allow_null=true) {
178183
Thread* thread = Thread::current_or_null_safe();
@@ -188,7 +193,7 @@ static JavaThread* get_current_thread(bool allow_null=true) {
188193
#define C2V_VMENTRY(result_type, name, signature) \
189194
JNIEXPORT result_type JNICALL c2v_ ## name signature { \
190195
JavaThread* thread = get_current_thread(); \
191-
if (thread == nullptr) { \
196+
if (thread == nullptr) { \
192197
env->ThrowNew(JNIJVMCI::InternalError::clazz(), \
193198
err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
194199
return; \
@@ -199,7 +204,7 @@ static JavaThread* get_current_thread(bool allow_null=true) {
199204
#define C2V_VMENTRY_(result_type, name, signature, result) \
200205
JNIEXPORT result_type JNICALL c2v_ ## name signature { \
201206
JavaThread* thread = get_current_thread(); \
202-
if (thread == nullptr) { \
207+
if (thread == nullptr) { \
203208
env->ThrowNew(JNIJVMCI::InternalError::clazz(), \
204209
err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
205210
return result; \
@@ -221,15 +226,15 @@ static JavaThread* get_current_thread(bool allow_null=true) {
221226
#define JNI_THROW(caller, name, msg) do { \
222227
jint __throw_res = env->ThrowNew(JNIJVMCI::name::clazz(), msg); \
223228
if (__throw_res != JNI_OK) { \
224-
tty->print_cr("Throwing " #name " in " caller " returned %d", __throw_res); \
229+
JVMCI_event_1("Throwing " #name " in " caller " returned %d", __throw_res); \
225230
} \
226231
return; \
227232
} while (0);
228233

229234
#define JNI_THROW_(caller, name, msg, result) do { \
230235
jint __throw_res = env->ThrowNew(JNIJVMCI::name::clazz(), msg); \
231236
if (__throw_res != JNI_OK) { \
232-
tty->print_cr("Throwing " #name " in " caller " returned %d", __throw_res); \
237+
JVMCI_event_1("Throwing " #name " in " caller " returned %d", __throw_res); \
233238
} \
234239
return result; \
235240
} while (0)
@@ -579,6 +584,7 @@ C2V_VMENTRY_0(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, ARGUMENT_PAIR(
579584
C2V_END
580585

581586
C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGUMENT_PAIR(accessing_klass), jint accessing_klass_loader, jboolean resolve))
587+
CompilerThreadCanCallJava canCallJava(thread, resolve); // Resolution requires Java calls
582588
JVMCIObject name = JVMCIENV->wrap(jname);
583589
const char* str = JVMCIENV->as_utf8_string(name);
584590
TempNewSymbol class_name = SymbolTable::new_symbol(str);
@@ -592,7 +598,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU
592598
if (val != nullptr) {
593599
if (strstr(val, "<trace>") != nullptr) {
594600
tty->print_cr("CompilerToVM.lookupType: %s", str);
595-
} else if (strstr(val, str) != nullptr) {
601+
} else if (strstr(str, val) != nullptr) {
596602
THROW_MSG_0(vmSymbols::java_lang_Exception(),
597603
err_msg("lookupTypeException: %s", str));
598604
}
@@ -938,6 +944,17 @@ C2V_VMENTRY_NULL(jobject, resolveFieldInPool, (JNIEnv* env, jobject, ARGUMENT_PA
938944
Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF);
939945
fieldDescriptor fd;
940946
methodHandle mh(THREAD, UNPACK_PAIR(Method, method));
947+
948+
Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF);
949+
int holder_index = cp->klass_ref_index_at(index, bc);
950+
if (!cp->tag_at(holder_index).is_klass() && !THREAD->can_call_java()) {
951+
// If the holder is not resolved in the constant pool and the current
952+
// thread cannot call Java, return null. This avoids a Java call
953+
// in LinkInfo to load the holder.
954+
Symbol* klass_name = cp->klass_ref_at_noresolve(index, bc);
955+
return nullptr;
956+
}
957+
941958
LinkInfo link_info(cp, index, mh, code, CHECK_NULL);
942959
LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_NULL);
943960
JVMCIPrimitiveArray info = JVMCIENV->wrap(info_handle);
@@ -2726,6 +2743,7 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool
27262743
return 0L;
27272744
}
27282745
PEER_JVMCIENV_FROM_THREAD(THREAD, !JVMCIENV->is_hotspot());
2746+
CompilerThreadCanCallJava canCallJava(thread, PEER_JVMCIENV->is_hotspot());
27292747
PEER_JVMCIENV->check_init(JVMCI_CHECK_0);
27302748

27312749
JVMCIEnv* thisEnv = JVMCIENV;
@@ -2945,18 +2963,21 @@ static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationA
29452963

29462964
C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass),
29472965
jobject filter, jint filter_length, jlong filter_klass_pointers))
2966+
CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support
29482967
InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass));
29492968
return get_encoded_annotation_data(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV);
29502969
C2V_END
29512970

29522971
C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(method),
29532972
jobject filter, jint filter_length, jlong filter_klass_pointers))
2973+
CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support
29542974
methodHandle method(THREAD, UNPACK_PAIR(Method, method));
29552975
return get_encoded_annotation_data(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV);
29562976
C2V_END
29572977

29582978
C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index,
29592979
jobject filter, jint filter_length, jlong filter_klass_pointers))
2980+
CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support
29602981
InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCIENV);
29612982
fieldDescriptor fd(holder, index);
29622983
return get_encoded_annotation_data(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV);
@@ -3013,6 +3034,7 @@ C2V_VMENTRY_0(jboolean, addFailedSpeculation, (JNIEnv* env, jobject, jlong faile
30133034
C2V_END
30143035

30153036
C2V_VMENTRY(void, callSystemExit, (JNIEnv* env, jobject, jint status))
3037+
CompilerThreadCanCallJava canCallJava(thread, true);
30163038
JavaValue result(T_VOID);
30173039
JavaCallArguments jargs(1);
30183040
jargs.push_int(status);

src/hotspot/share/jvmci/jvmciEnv.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,15 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
448448
private:
449449
const Handle& _throwable;
450450

451+
char* print_throwable_to_buffer(Handle throwable, jlong buffer, int buffer_size) {
452+
char* char_buffer = (char*) buffer + 4;
453+
stringStream st(char_buffer, (size_t) buffer_size - 4);
454+
java_lang_Throwable::print_stack_trace(throwable, &st);
455+
u4 len = (u4) st.size();
456+
*((u4*) buffer) = len;
457+
return char_buffer;
458+
}
459+
451460
bool handle_pending_exception(JavaThread* THREAD, jlong buffer, int buffer_size) {
452461
if (HAS_PENDING_EXCEPTION) {
453462
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
@@ -457,11 +466,7 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
457466
JVMCI_event_1("error translating exception: OutOfMemoryError");
458467
decode(THREAD, _encode_oome_fail, 0L);
459468
} else {
460-
char* char_buffer = (char*) buffer + 4;
461-
stringStream st(char_buffer, (size_t) buffer_size - 4);
462-
java_lang_Throwable::print_stack_trace(throwable, &st);
463-
u4 len = (u4) st.size();
464-
*((u4*) buffer) = len;
469+
char* char_buffer = print_throwable_to_buffer(throwable, buffer, buffer_size);
465470
JVMCI_event_1("error translating exception: %s", char_buffer);
466471
decode(THREAD, _encode_fail, buffer);
467472
}
@@ -471,6 +476,13 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
471476
}
472477

473478
int encode(JavaThread* THREAD, jlong buffer, int buffer_size) {
479+
if (!THREAD->can_call_java()) {
480+
char* char_buffer = print_throwable_to_buffer(_throwable, buffer, buffer_size);
481+
const char* detail = log_is_enabled(Info, exceptions) ? "" : " (-Xlog:exceptions may give more detail)";
482+
JVMCI_event_1("cannot call Java to translate exception%s: %s", detail, char_buffer);
483+
decode(THREAD, _encode_fail, buffer);
484+
return 0;
485+
}
474486
Klass* vmSupport = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_VMSupport(), true, THREAD);
475487
if (handle_pending_exception(THREAD, buffer, buffer_size)) {
476488
return 0;
@@ -1311,6 +1323,7 @@ JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS)
13111323
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
13121324
jboolean exception = false;
13131325
if (is_hotspot()) {
1326+
CompilerThreadCanCallJava ccj(THREAD, true);
13141327
JavaValue result(T_OBJECT);
13151328
JavaCallArguments args;
13161329
args.push_long(pointer);

0 commit comments

Comments
 (0)