8276658: Clean up JNI local handles code

Reviewed-by: dholmes, pchilanomate
This commit is contained in:
Coleen Phillimore 2021-11-12 16:17:15 +00:00
parent aeba653034
commit 3b2585c02b
25 changed files with 123 additions and 350 deletions

View file

@ -87,7 +87,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
(void)CURRENT_ENV->get_object(holder); (void)CURRENT_ENV->get_object(holder);
} }
Thread *thread = Thread::current(); JavaThread *thread = JavaThread::current();
if (ciObjectFactory::is_initialized()) { if (ciObjectFactory::is_initialized()) {
_loader = JNIHandles::make_local(thread, ik->class_loader()); _loader = JNIHandles::make_local(thread, ik->class_loader());
_protection_domain = JNIHandles::make_local(thread, _protection_domain = JNIHandles::make_local(thread,

View file

@ -2200,7 +2200,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
} }
// Allocate a new set of JNI handles. // Allocate a new set of JNI handles.
push_jni_handle_block(); JNIHandleMark jhm(thread);
Method* target_handle = task->method(); Method* target_handle = task->method();
int compilable = ciEnv::MethodCompilable; int compilable = ciEnv::MethodCompilable;
const char* failure_reason = NULL; const char* failure_reason = NULL;
@ -2319,9 +2319,6 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
post_compilation_event(event, task); post_compilation_event(event, task);
} }
} }
// Remove the JNI handle block after the ciEnv destructor has run in
// the previous block.
pop_jni_handle_block();
if (failure_reason != NULL) { if (failure_reason != NULL) {
task->set_failure_reason(failure_reason, failure_reason_on_C_heap); task->set_failure_reason(failure_reason, failure_reason_on_C_heap);
@ -2482,38 +2479,6 @@ void CompileBroker::update_compile_perf_data(CompilerThread* thread, const metho
counters->set_compile_type((jlong) last_compile_type); counters->set_compile_type((jlong) last_compile_type);
} }
// ------------------------------------------------------------------
// CompileBroker::push_jni_handle_block
//
// Push on a new block of JNI handles.
void CompileBroker::push_jni_handle_block() {
JavaThread* thread = JavaThread::current();
// Allocate a new block for JNI handles.
// Inlined code from jni_PushLocalFrame()
JNIHandleBlock* java_handles = thread->active_handles();
JNIHandleBlock* compile_handles = JNIHandleBlock::allocate_block(thread);
assert(compile_handles != NULL && java_handles != NULL, "should not be NULL");
compile_handles->set_pop_frame_link(java_handles); // make sure java handles get gc'd.
thread->set_active_handles(compile_handles);
}
// ------------------------------------------------------------------
// CompileBroker::pop_jni_handle_block
//
// Pop off the current block of JNI handles.
void CompileBroker::pop_jni_handle_block() {
JavaThread* thread = JavaThread::current();
// Release our JNI handle block
JNIHandleBlock* compile_handles = thread->active_handles();
JNIHandleBlock* java_handles = compile_handles->pop_frame_link();
thread->set_active_handles(java_handles);
compile_handles->set_pop_frame_link(NULL);
JNIHandleBlock::release_block(compile_handles, thread); // may block
}
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// CompileBroker::collect_statistics // CompileBroker::collect_statistics
// //

View file

@ -259,8 +259,6 @@ class CompileBroker: AllStatic {
int compilable, const char* failure_reason); int compilable, const char* failure_reason);
static void update_compile_perf_data(CompilerThread *thread, const methodHandle& method, bool is_osr); static void update_compile_perf_data(CompilerThread *thread, const methodHandle& method, bool is_osr);
static void push_jni_handle_block();
static void pop_jni_handle_block();
static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task); static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task);
static void compile_method_base(const methodHandle& method, static void compile_method_base(const methodHandle& method,

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -42,9 +42,6 @@ void ConcurrentGCThread::create_and_start(ThreadPriority prio) {
} }
void ConcurrentGCThread::run() { void ConcurrentGCThread::run() {
// Setup handle area
set_active_handles(JNIHandleBlock::allocate_block());
// Wait for initialization to complete // Wait for initialization to complete
wait_init_completed(); wait_init_completed();

View file

@ -55,53 +55,6 @@ bool register_jfr_dcmds() {
return true; return true;
} }
// JNIHandle management
// ------------------------------------------------------------------
// push_jni_handle_block
//
// Push on a new block of JNI handles.
static void push_jni_handle_block(JavaThread* const thread) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
// Allocate a new block for JNI handles.
// Inlined code from jni_PushLocalFrame()
JNIHandleBlock* prev_handles = thread->active_handles();
JNIHandleBlock* entry_handles = JNIHandleBlock::allocate_block(thread);
assert(entry_handles != NULL && prev_handles != NULL, "should not be NULL");
entry_handles->set_pop_frame_link(prev_handles); // make sure prev handles get gc'd.
thread->set_active_handles(entry_handles);
}
// ------------------------------------------------------------------
// pop_jni_handle_block
//
// Pop off the current block of JNI handles.
static void pop_jni_handle_block(JavaThread* const thread) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
// Release our JNI handle block
JNIHandleBlock* entry_handles = thread->active_handles();
JNIHandleBlock* prev_handles = entry_handles->pop_frame_link();
// restore
thread->set_active_handles(prev_handles);
entry_handles->set_pop_frame_link(NULL);
JNIHandleBlock::release_block(entry_handles, thread); // may block
}
class JNIHandleBlockManager : public StackObj {
private:
JavaThread* const _thread;
public:
JNIHandleBlockManager(JavaThread* thread) : _thread(thread) {
push_jni_handle_block(_thread);
}
~JNIHandleBlockManager() {
pop_jni_handle_block(_thread);
}
};
static bool is_module_available(outputStream* output, TRAPS) { static bool is_module_available(outputStream* output, TRAPS) {
return JfrJavaSupport::is_jdk_jfr_module_available(output, THREAD); return JfrJavaSupport::is_jdk_jfr_module_available(output, THREAD);
} }
@ -223,7 +176,7 @@ void JfrDCmd::invoke(JfrJavaArguments& method, TRAPS) const {
constructor_args.set_klass(javaClass(), CHECK); constructor_args.set_klass(javaClass(), CHECK);
HandleMark hm(THREAD); HandleMark hm(THREAD);
JNIHandleBlockManager jni_handle_management(THREAD); JNIHandleMark jni_handle_management(THREAD);
const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK); const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
@ -494,7 +447,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
} }
HandleMark hm(THREAD); HandleMark hm(THREAD);
JNIHandleBlockManager jni_handle_management(THREAD); JNIHandleMark jni_handle_management(THREAD);
JavaValue result(T_OBJECT); JavaValue result(T_OBJECT);
JfrJavaArguments constructor_args(&result); JfrJavaArguments constructor_args(&result);

View file

@ -71,7 +71,7 @@ static void check_new_unstarted_java_thread(JavaThread* t) {
*/ */
jobject JfrJavaSupport::local_jni_handle(const oop obj, JavaThread* t) { jobject JfrJavaSupport::local_jni_handle(const oop obj, JavaThread* t) {
DEBUG_ONLY(check_java_thread_in_vm(t)); DEBUG_ONLY(check_java_thread_in_vm(t));
return t->active_handles()->allocate_handle(obj); return t->active_handles()->allocate_handle(t, obj);
} }
jobject JfrJavaSupport::local_jni_handle(const jobject handle, JavaThread* t) { jobject JfrJavaSupport::local_jni_handle(const jobject handle, JavaThread* t) {

View file

@ -899,7 +899,7 @@ GrowableArray<ScopeValue*>* CodeInstaller::record_virtual_objects(JVMCIObject de
} }
Klass* klass = jvmci_env()->asKlass(type); Klass* klass = jvmci_env()->asKlass(type);
oop javaMirror = klass->java_mirror(); oop javaMirror = klass->java_mirror();
ScopeValue *klass_sv = new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror)); ScopeValue *klass_sv = new ConstantOopWriteValue(JNIHandles::make_local(javaMirror));
ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv); ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv);
if (id < 0 || id >= objects->length()) { if (id < 0 || id >= objects->length()) {
JVMCI_ERROR_NULL("virtual object id %d out of bounds", id); JVMCI_ERROR_NULL("virtual object id %d out of bounds", id);

View file

@ -86,29 +86,6 @@ static void requireInHotSpot(const char* caller, JVMCI_TRAPS) {
} }
} }
void JNIHandleMark::push_jni_handle_block(JavaThread* thread) {
if (thread != NULL) {
// Allocate a new block for JNI handles.
// Inlined code from jni_PushLocalFrame()
JNIHandleBlock* java_handles = thread->active_handles();
JNIHandleBlock* compile_handles = JNIHandleBlock::allocate_block(thread);
assert(compile_handles != NULL && java_handles != NULL, "should not be NULL");
compile_handles->set_pop_frame_link(java_handles);
thread->set_active_handles(compile_handles);
}
}
void JNIHandleMark::pop_jni_handle_block(JavaThread* thread) {
if (thread != NULL) {
// Release our JNI handle block
JNIHandleBlock* compile_handles = thread->active_handles();
JNIHandleBlock* java_handles = compile_handles->pop_frame_link();
thread->set_active_handles(java_handles);
compile_handles->set_pop_frame_link(NULL);
JNIHandleBlock::release_block(compile_handles, thread); // may block
}
}
class JVMCITraceMark : public StackObj { class JVMCITraceMark : public StackObj {
const char* _msg; const char* _msg;
public: public:

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -173,15 +173,4 @@ class JavaArgumentUnboxer : public SignatureIterator {
} }
}; };
class JNIHandleMark : public StackObj {
JavaThread* _thread;
public:
JNIHandleMark(JavaThread* thread) : _thread(thread) { push_jni_handle_block(thread); }
~JNIHandleMark() { pop_jni_handle_block(_thread); }
private:
static void push_jni_handle_block(JavaThread* thread);
static void pop_jni_handle_block(JavaThread* thread);
};
#endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP #endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP

View file

@ -639,11 +639,8 @@ JNI_ENTRY(jint, jni_PushLocalFrame(JNIEnv *env, jint capacity))
HOTSPOT_JNI_PUSHLOCALFRAME_RETURN((uint32_t)JNI_ERR); HOTSPOT_JNI_PUSHLOCALFRAME_RETURN((uint32_t)JNI_ERR);
return JNI_ERR; return JNI_ERR;
} }
JNIHandleBlock* old_handles = thread->active_handles();
JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread); thread->push_jni_handle_block();
assert(new_handles != NULL, "should not be NULL");
new_handles->set_pop_frame_link(old_handles);
thread->set_active_handles(new_handles);
jint ret = JNI_OK; jint ret = JNI_OK;
HOTSPOT_JNI_PUSHLOCALFRAME_RETURN(ret); HOTSPOT_JNI_PUSHLOCALFRAME_RETURN(ret);
return ret; return ret;

View file

@ -1510,7 +1510,7 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje
return JVMTI_ERROR_OUT_OF_MEMORY; return JVMTI_ERROR_OUT_OF_MEMORY;
} }
for (jint idx = 0; idx < len; idx++) { for (jint idx = 0; idx < len; idx++) {
array[idx] = JNIHandles::make_local(Thread::current(), _tbl->at(idx).resolve()); array[idx] = JNIHandles::make_local(_tbl->at(idx).resolve());
} }
_tbl = NULL; _tbl = NULL;
*modules_ptr = array; *modules_ptr = array;

View file

@ -141,20 +141,11 @@ private:
JavaThread *_thread; JavaThread *_thread;
JNIEnv* _jni_env; JNIEnv* _jni_env;
JvmtiThreadState::ExceptionState _saved_exception_state; JvmtiThreadState::ExceptionState _saved_exception_state;
#if 0
JNIHandleBlock* _hblock;
#endif
public: public:
JvmtiEventMark(JavaThread *thread) : _thread(thread), JvmtiEventMark(JavaThread *thread) : _thread(thread),
_jni_env(thread->jni_environment()), _jni_env(thread->jni_environment()),
_saved_exception_state(JvmtiThreadState::ES_CLEARED) { _saved_exception_state(JvmtiThreadState::ES_CLEARED) {
#if 0
_hblock = thread->active_handles();
_hblock->clear_thoroughly(); // so we can be safe
#else
// we want to use the code above - but that needs the JNIHandle changes - later...
// for now, steal JNI push local frame code
JvmtiThreadState *state = thread->jvmti_thread_state(); JvmtiThreadState *state = thread->jvmti_thread_state();
// we are before an event. // we are before an event.
// Save current jvmti thread exception state. // Save current jvmti thread exception state.
@ -162,31 +153,13 @@ public:
_saved_exception_state = state->get_exception_state(); _saved_exception_state = state->get_exception_state();
} }
JNIHandleBlock* old_handles = thread->active_handles(); thread->push_jni_handle_block();
JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread);
assert(new_handles != NULL, "should not be NULL");
new_handles->set_pop_frame_link(old_handles);
thread->set_active_handles(new_handles);
#endif
assert(thread == JavaThread::current(), "thread must be current!"); assert(thread == JavaThread::current(), "thread must be current!");
thread->frame_anchor()->make_walkable(thread); thread->frame_anchor()->make_walkable(thread);
}; };
~JvmtiEventMark() { ~JvmtiEventMark() {
#if 0 _thread->pop_jni_handle_block();
_hblock->clear(); // for consistency with future correct behavior
#else
// we want to use the code above - but that needs the JNIHandle changes - later...
// for now, steal JNI pop local frame code
JNIHandleBlock* old_handles = _thread->active_handles();
JNIHandleBlock* new_handles = old_handles->pop_frame_link();
assert(new_handles != NULL, "should not be NULL");
_thread->set_active_handles(new_handles);
// Note that we set the pop_frame_link to NULL explicitly, otherwise
// the release_block call will release the blocks.
old_handles->set_pop_frame_link(NULL);
JNIHandleBlock::release_block(old_handles, _thread); // may block
#endif
JvmtiThreadState* state = _thread->jvmti_thread_state(); JvmtiThreadState* state = _thread->jvmti_thread_state();
// we are continuing after an event. // we are continuing after an event.
@ -196,13 +169,7 @@ public:
} }
} }
#if 0
jobject to_jobject(oop obj) { return obj == NULL? NULL : _hblock->allocate_handle_fast(obj); }
#else
// we want to use the code above - but that needs the JNIHandle changes - later...
// for now, use regular make_local
jobject to_jobject(oop obj) { return JNIHandles::make_local(_thread,obj); } jobject to_jobject(oop obj) { return JNIHandles::make_local(_thread,obj); }
#endif
jclass to_jclass(Klass* klass) { return (klass == NULL ? NULL : (jclass)to_jobject(klass->java_mirror())); } jclass to_jclass(Klass* klass) { return (klass == NULL ? NULL : (jclass)to_jobject(klass->java_mirror())); }

View file

@ -56,18 +56,17 @@ void jni_handles_init() {
} }
jobject JNIHandles::make_local(oop obj) { jobject JNIHandles::make_local(oop obj) {
return make_local(Thread::current(), obj); return make_local(JavaThread::current(), obj);
} }
// Used by NewLocalRef which requires NULL on out-of-memory // Used by NewLocalRef which requires NULL on out-of-memory
jobject JNIHandles::make_local(Thread* thread, oop obj, AllocFailType alloc_failmode) { jobject JNIHandles::make_local(JavaThread* thread, oop obj, AllocFailType alloc_failmode) {
if (obj == NULL) { if (obj == NULL) {
return NULL; // ignore null handles return NULL; // ignore null handles
} else { } else {
assert(oopDesc::is_oop(obj), "not an oop"); assert(oopDesc::is_oop(obj), "not an oop");
assert(thread->is_Java_thread(), "not a Java thread");
assert(!current_thread_in_native(), "must not be in native"); assert(!current_thread_in_native(), "must not be in native");
return thread->active_handles()->allocate_handle(obj, alloc_failmode); return thread->active_handles()->allocate_handle(thread, obj, alloc_failmode);
} }
} }
@ -187,7 +186,7 @@ inline bool is_storage_handle(const OopStorage* storage, const oop* ptr) {
} }
jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) { jobjectRefType JNIHandles::handle_type(JavaThread* thread, jobject handle) {
assert(handle != NULL, "precondition"); assert(handle != NULL, "precondition");
jobjectRefType result = JNIInvalidRefType; jobjectRefType result = JNIInvalidRefType;
if (is_jweak(handle)) { if (is_jweak(handle)) {
@ -205,9 +204,7 @@ jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) {
case OopStorage::INVALID_ENTRY: case OopStorage::INVALID_ENTRY:
// Not in global storage. Might be a local handle. // Not in global storage. Might be a local handle.
if (is_local_handle(thread, handle) || if (is_local_handle(thread, handle) || is_frame_handle(thread, handle)) {
(thread->is_Java_thread() &&
is_frame_handle(JavaThread::cast(thread), handle))) {
result = JNILocalRefType; result = JNILocalRefType;
} }
break; break;
@ -220,7 +217,7 @@ jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) {
} }
bool JNIHandles::is_local_handle(Thread* thread, jobject handle) { bool JNIHandles::is_local_handle(JavaThread* thread, jobject handle) {
assert(handle != NULL, "precondition"); assert(handle != NULL, "precondition");
JNIHandleBlock* block = thread->active_handles(); JNIHandleBlock* block = thread->active_handles();
@ -305,12 +302,7 @@ bool JNIHandles::current_thread_in_native() {
JavaThread::cast(thread)->thread_state() == _thread_in_native); JavaThread::cast(thread)->thread_state() == _thread_in_native);
} }
int JNIHandleBlock::_blocks_allocated = 0; int JNIHandleBlock::_blocks_allocated = 0;
JNIHandleBlock* JNIHandleBlock::_block_free_list = NULL;
#ifndef PRODUCT
JNIHandleBlock* JNIHandleBlock::_block_list = NULL;
#endif
static inline bool is_tagged_free_list(uintptr_t value) { static inline bool is_tagged_free_list(uintptr_t value) {
return (value & 1u) != 0; return (value & 1u) != 0;
@ -343,23 +335,17 @@ void JNIHandleBlock::zap() {
} }
#endif // ASSERT #endif // ASSERT
JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread, AllocFailType alloc_failmode) { JNIHandleBlock* JNIHandleBlock::allocate_block(JavaThread* thread, AllocFailType alloc_failmode) {
assert(thread == NULL || thread == Thread::current(), "sanity check"); // The VM thread can allocate a handle block in behalf of another thread during a safepoint.
assert(thread == NULL || thread == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"sanity check");
JNIHandleBlock* block; JNIHandleBlock* block;
// Check the thread-local free list for a block so we don't // Check the thread-local free list for a block so we don't
// have to acquire a mutex. // have to acquire a mutex.
if (thread != NULL && thread->free_handle_block() != NULL) { if (thread != NULL && thread->free_handle_block() != NULL) {
block = thread->free_handle_block(); block = thread->free_handle_block();
thread->set_free_handle_block(block->_next); thread->set_free_handle_block(block->_next);
} } else {
else {
// locking with safepoint checking introduces a potential deadlock:
// - we would hold JNIHandleBlockFreeList_lock and then Threads_lock
// - another would hold Threads_lock (jni_AttachCurrentThread) and then
// JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block)
MutexLocker ml(JNIHandleBlockFreeList_lock,
Mutex::_no_safepoint_check_flag);
if (_block_free_list == NULL) {
// Allocate new block // Allocate new block
if (alloc_failmode == AllocFailStrategy::RETURN_NULL) { if (alloc_failmode == AllocFailStrategy::RETURN_NULL) {
block = new (std::nothrow) JNIHandleBlock(); block = new (std::nothrow) JNIHandleBlock();
@ -369,18 +355,8 @@ JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread, AllocFailType all
} else { } else {
block = new JNIHandleBlock(); block = new JNIHandleBlock();
} }
_blocks_allocated++; Atomic::inc(&_blocks_allocated);
block->zap(); block->zap();
#ifndef PRODUCT
// Link new block to list of all allocated blocks
block->_block_list_link = _block_list;
_block_list = block;
#endif
} else {
// Get block from free list
block = _block_free_list;
_block_free_list = _block_free_list->_next;
}
} }
block->_top = 0; block->_top = 0;
block->_next = NULL; block->_next = NULL;
@ -394,7 +370,7 @@ JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread, AllocFailType all
} }
void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) { void JNIHandleBlock::release_block(JNIHandleBlock* block, JavaThread* thread) {
assert(thread == NULL || thread == Thread::current(), "sanity check"); assert(thread == NULL || thread == Thread::current(), "sanity check");
JNIHandleBlock* pop_frame_link = block->pop_frame_link(); JNIHandleBlock* pop_frame_link = block->pop_frame_link();
// Put returned block at the beginning of the thread-local free list. // Put returned block at the beginning of the thread-local free list.
@ -415,20 +391,8 @@ void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) {
block = NULL; block = NULL;
} }
if (block != NULL) { if (block != NULL) {
// Return blocks to free list Atomic::dec(&_blocks_allocated);
// locking with safepoint checking introduces a potential deadlock: delete block;
// - we would hold JNIHandleBlockFreeList_lock and then Threads_lock
// - another would hold Threads_lock (jni_AttachCurrentThread) and then
// JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block)
MutexLocker ml(JNIHandleBlockFreeList_lock,
Mutex::_no_safepoint_check_flag);
while (block != NULL) {
block->zap();
JNIHandleBlock* next = block->_next;
block->_next = _block_free_list;
_block_free_list = block;
block = next;
}
} }
if (pop_frame_link != NULL) { if (pop_frame_link != NULL) {
// As a sanity check we release blocks pointed to by the pop_frame_link. // As a sanity check we release blocks pointed to by the pop_frame_link.
@ -468,7 +432,7 @@ void JNIHandleBlock::oops_do(OopClosure* f) {
} }
jobject JNIHandleBlock::allocate_handle(oop obj, AllocFailType alloc_failmode) { jobject JNIHandleBlock::allocate_handle(JavaThread* caller, oop obj, AllocFailType alloc_failmode) {
assert(Universe::heap()->is_in(obj), "sanity check"); assert(Universe::heap()->is_in(obj), "sanity check");
if (_top == 0) { if (_top == 0) {
// This is the first allocation or the initial block got zapped when // This is the first allocation or the initial block got zapped when
@ -516,26 +480,21 @@ jobject JNIHandleBlock::allocate_handle(oop obj, AllocFailType alloc_failmode) {
if (_last->_next != NULL) { if (_last->_next != NULL) {
// update last and retry // update last and retry
_last = _last->_next; _last = _last->_next;
return allocate_handle(obj, alloc_failmode); return allocate_handle(caller, obj, alloc_failmode);
} }
// No space available, we have to rebuild free list or expand // No space available, we have to rebuild free list or expand
if (_allocate_before_rebuild == 0) { if (_allocate_before_rebuild == 0) {
rebuild_free_list(); // updates _allocate_before_rebuild counter rebuild_free_list(); // updates _allocate_before_rebuild counter
} else { } else {
// Append new block _last->_next = JNIHandleBlock::allocate_block(caller, alloc_failmode);
Thread* thread = Thread::current();
Handle obj_handle(thread, obj);
// This can block, so we need to preserve obj across call.
_last->_next = JNIHandleBlock::allocate_block(thread, alloc_failmode);
if (_last->_next == NULL) { if (_last->_next == NULL) {
return NULL; return NULL;
} }
_last = _last->_next; _last = _last->_next;
_allocate_before_rebuild--; _allocate_before_rebuild--;
obj = obj_handle();
} }
return allocate_handle(obj, alloc_failmode); // retry return allocate_handle(caller, obj, alloc_failmode); // retry
} }
void JNIHandleBlock::rebuild_free_list() { void JNIHandleBlock::rebuild_free_list() {
@ -612,46 +571,3 @@ const size_t JNIHandleBlock::get_number_of_live_handles() {
size_t JNIHandleBlock::memory_usage() const { size_t JNIHandleBlock::memory_usage() const {
return length() * sizeof(JNIHandleBlock); return length() * sizeof(JNIHandleBlock);
} }
#ifndef PRODUCT
bool JNIHandles::is_local_handle(jobject handle) {
return JNIHandleBlock::any_contains(handle);
}
bool JNIHandleBlock::any_contains(jobject handle) {
assert(handle != NULL, "precondition");
for (JNIHandleBlock* current = _block_list; current != NULL; current = current->_block_list_link) {
if (current->contains(handle)) {
return true;
}
}
return false;
}
void JNIHandleBlock::print_statistics() {
int used_blocks = 0;
int free_blocks = 0;
int used_handles = 0;
int free_handles = 0;
JNIHandleBlock* block = _block_list;
while (block != NULL) {
if (block->_top > 0) {
used_blocks++;
} else {
free_blocks++;
}
used_handles += block->_top;
free_handles += (block_size_in_oops - block->_top);
block = block->_block_list_link;
}
tty->print_cr("JNIHandleBlocks statistics");
tty->print_cr("- blocks allocated: %d", used_blocks + free_blocks);
tty->print_cr("- blocks in use: %d", used_blocks);
tty->print_cr("- blocks free: %d", free_blocks);
tty->print_cr("- handles in use: %d", used_handles);
tty->print_cr("- handles free: %d", free_handles);
}
#endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -84,7 +84,7 @@ class JNIHandles : AllStatic {
// Local handles // Local handles
static jobject make_local(oop obj); static jobject make_local(oop obj);
static jobject make_local(Thread* thread, oop obj, // Faster version when current thread is known static jobject make_local(JavaThread* thread, oop obj, // Faster version when current thread is known
AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
inline static void destroy_local(jobject handle); inline static void destroy_local(jobject handle);
@ -104,20 +104,15 @@ class JNIHandles : AllStatic {
static void print(); static void print();
static void verify(); static void verify();
// The category predicates all require handle != NULL. // The category predicates all require handle != NULL.
static bool is_local_handle(Thread* thread, jobject handle); static bool is_local_handle(JavaThread* thread, jobject handle);
static bool is_frame_handle(JavaThread* thread, jobject handle); static bool is_frame_handle(JavaThread* thread, jobject handle);
static bool is_global_handle(jobject handle); static bool is_global_handle(jobject handle);
static bool is_weak_global_handle(jobject handle); static bool is_weak_global_handle(jobject handle);
static size_t global_handle_memory_usage(); static size_t global_handle_memory_usage();
static size_t weak_global_handle_memory_usage(); static size_t weak_global_handle_memory_usage();
#ifndef PRODUCT
// Is handle from any local block of any thread?
static bool is_local_handle(jobject handle);
#endif
// precondition: handle != NULL. // precondition: handle != NULL.
static jobjectRefType handle_type(Thread* thread, jobject handle); static jobjectRefType handle_type(JavaThread* thread, jobject handle);
// Garbage collection support(global handles only, local handles are traversed from thread) // Garbage collection support(global handles only, local handles are traversed from thread)
// Traversal of regular global handles // Traversal of regular global handles
@ -145,6 +140,7 @@ class JNIHandleBlock : public CHeapObj<mtInternal> {
uintptr_t _handles[block_size_in_oops]; // The handles uintptr_t _handles[block_size_in_oops]; // The handles
int _top; // Index of next unused handle int _top; // Index of next unused handle
int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list
JNIHandleBlock* _next; // Link to next block JNIHandleBlock* _next; // Link to next block
// The following instance variables are only used by the first block in a chain. // The following instance variables are only used by the first block in a chain.
@ -152,17 +148,9 @@ class JNIHandleBlock : public CHeapObj<mtInternal> {
JNIHandleBlock* _last; // Last block in use JNIHandleBlock* _last; // Last block in use
JNIHandleBlock* _pop_frame_link; // Block to restore on PopLocalFrame call JNIHandleBlock* _pop_frame_link; // Block to restore on PopLocalFrame call
uintptr_t* _free_list; // Handle free list uintptr_t* _free_list; // Handle free list
int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list
// Check JNI, "planned capacity" for current frame (or push/ensure) // Check JNI, "planned capacity" for current frame (or push/ensure)
size_t _planned_capacity; size_t _planned_capacity;
#ifndef PRODUCT
JNIHandleBlock* _block_list_link; // Link for list below
static JNIHandleBlock* _block_list; // List of all allocated blocks (for debugging only)
#endif
static JNIHandleBlock* _block_free_list; // Free list of currently unused blocks
static int _blocks_allocated; // For debugging/printing static int _blocks_allocated; // For debugging/printing
// Fill block with bad_handle values // Fill block with bad_handle values
@ -176,11 +164,11 @@ class JNIHandleBlock : public CHeapObj<mtInternal> {
public: public:
// Handle allocation // Handle allocation
jobject allocate_handle(oop obj, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); jobject allocate_handle(JavaThread* caller, oop obj, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
// Block allocation and block free list management // Block allocation and block free list management
static JNIHandleBlock* allocate_block(Thread* thread = NULL, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); static JNIHandleBlock* allocate_block(JavaThread* thread = NULL, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
static void release_block(JNIHandleBlock* block, Thread* thread = NULL); static void release_block(JNIHandleBlock* block, JavaThread* thread = NULL);
// JNI PushLocalFrame/PopLocalFrame support // JNI PushLocalFrame/PopLocalFrame support
JNIHandleBlock* pop_frame_link() const { return _pop_frame_link; } JNIHandleBlock* pop_frame_link() const { return _pop_frame_link; }
@ -203,10 +191,6 @@ class JNIHandleBlock : public CHeapObj<mtInternal> {
bool contains(jobject handle) const; // Does this block contain handle bool contains(jobject handle) const; // Does this block contain handle
size_t length() const; // Length of chain starting with this block size_t length() const; // Length of chain starting with this block
size_t memory_usage() const; size_t memory_usage() const;
#ifndef PRODUCT
static bool any_contains(jobject handle); // Does any block currently in use contain handle
static void print_statistics();
#endif
}; };
#endif // SHARE_RUNTIME_JNIHANDLES_HPP #endif // SHARE_RUNTIME_JNIHANDLES_HPP

View file

@ -48,7 +48,6 @@ Mutex* Module_lock = NULL;
Mutex* CompiledIC_lock = NULL; Mutex* CompiledIC_lock = NULL;
Mutex* InlineCacheBuffer_lock = NULL; Mutex* InlineCacheBuffer_lock = NULL;
Mutex* VMStatistic_lock = NULL; Mutex* VMStatistic_lock = NULL;
Mutex* JNIHandleBlockFreeList_lock = NULL;
Mutex* JmethodIdCreation_lock = NULL; Mutex* JmethodIdCreation_lock = NULL;
Mutex* JfieldIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL;
Monitor* JNICritical_lock = NULL; Monitor* JNICritical_lock = NULL;
@ -259,7 +258,6 @@ void mutex_init() {
def(SharedDictionary_lock , PaddedMutex , safepoint); def(SharedDictionary_lock , PaddedMutex , safepoint);
def(VMStatistic_lock , PaddedMutex , safepoint); def(VMStatistic_lock , PaddedMutex , safepoint);
def(JNIHandleBlockFreeList_lock , PaddedMutex , nosafepoint-1); // handles are used by VM thread
def(SignatureHandlerLibrary_lock , PaddedMutex , safepoint); def(SignatureHandlerLibrary_lock , PaddedMutex , safepoint);
def(SymbolArena_lock , PaddedMutex , nosafepoint); def(SymbolArena_lock , PaddedMutex , nosafepoint);
def(ExceptionCache_lock , PaddedMutex , safepoint); def(ExceptionCache_lock , PaddedMutex , safepoint);

View file

@ -40,7 +40,6 @@ extern Mutex* Module_lock; // a lock on module and package
extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access
extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer
extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in

View file

@ -234,7 +234,6 @@ int WatcherThread::sleep() const {
void WatcherThread::run() { void WatcherThread::run() {
assert(this == watcher_thread(), "just checking"); assert(this == watcher_thread(), "just checking");
this->set_active_handles(JNIHandleBlock::allocate_block());
while (true) { while (true) {
assert(watcher_thread() == Thread::current(), "thread consistency check"); assert(watcher_thread() == Thread::current(), "thread consistency check");
assert(watcher_thread() == this, "thread consistency check"); assert(watcher_thread() == this, "thread consistency check");

View file

@ -1169,13 +1169,6 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) {
st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr)); st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr));
return; return;
} }
#ifndef PRODUCT
// we don't keep the block list in product mode
if (JNIHandles::is_local_handle((jobject) addr)) {
st->print_cr(INTPTR_FORMAT " is a local jni handle", p2i(addr));
return;
}
#endif
} }
// Check if addr belongs to a Java thread. // Check if addr belongs to a Java thread.

View file

@ -220,8 +220,6 @@ Thread::Thread() {
DEBUG_ONLY(_current_resource_mark = NULL;) DEBUG_ONLY(_current_resource_mark = NULL;)
set_handle_area(new (mtThread) HandleArea(NULL)); set_handle_area(new (mtThread) HandleArea(NULL));
set_metadata_handles(new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(30, mtClass)); set_metadata_handles(new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(30, mtClass));
set_active_handles(NULL);
set_free_handle_block(NULL);
set_last_handle_mark(NULL); set_last_handle_mark(NULL);
DEBUG_ONLY(_missed_ic_stub_refill_verifier = NULL); DEBUG_ONLY(_missed_ic_stub_refill_verifier = NULL);
@ -536,9 +534,6 @@ bool Thread::claim_par_threads_do(uintx claim_token) {
} }
void Thread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { void Thread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) {
if (active_handles() != NULL) {
active_handles()->oops_do(f);
}
// Do oop for ThreadShadow // Do oop for ThreadShadow
f->do_oop((oop*)&_pending_exception); f->do_oop((oop*)&_pending_exception);
handle_area()->oops_do(f); handle_area()->oops_do(f);
@ -1003,6 +998,8 @@ JavaThread::JavaThread() :
_current_pending_monitor(NULL), _current_pending_monitor(NULL),
_current_pending_monitor_is_from_java(true), _current_pending_monitor_is_from_java(true),
_current_waiting_monitor(NULL), _current_waiting_monitor(NULL),
_active_handles(NULL),
_free_handle_block(NULL),
_Stalled(0), _Stalled(0),
_monitor_chunks(nullptr), _monitor_chunks(nullptr),
@ -1930,6 +1927,28 @@ void JavaThread::verify_frame_info() {
} }
#endif #endif
// Push on a new block of JNI handles.
void JavaThread::push_jni_handle_block() {
// Allocate a new block for JNI handles.
// Inlined code from jni_PushLocalFrame()
JNIHandleBlock* old_handles = active_handles();
JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(this);
assert(old_handles != NULL && new_handles != NULL, "should not be NULL");
new_handles->set_pop_frame_link(old_handles); // make sure java handles get gc'd.
set_active_handles(new_handles);
}
// Pop off the current block of JNI handles.
void JavaThread::pop_jni_handle_block() {
// Release our JNI handle block
JNIHandleBlock* old_handles = active_handles();
JNIHandleBlock* new_handles = old_handles->pop_frame_link();
assert(new_handles != nullptr, "should never set active handles to null");
set_active_handles(new_handles);
old_handles->set_pop_frame_link(NULL);
JNIHandleBlock::release_block(old_handles, this);
}
void JavaThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { void JavaThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) {
// Verify that the deferred card marks have been flushed. // Verify that the deferred card marks have been flushed.
assert(deferred_card_mark().is_empty(), "Should be empty during GC"); assert(deferred_card_mark().is_empty(), "Should be empty during GC");
@ -1937,6 +1956,10 @@ void JavaThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) {
// Traverse the GCHandles // Traverse the GCHandles
Thread::oops_do_no_frames(f, cf); Thread::oops_do_no_frames(f, cf);
if (active_handles() != NULL) {
active_handles()->oops_do(f);
}
DEBUG_ONLY(verify_frame_info();) DEBUG_ONLY(verify_frame_info();)
if (has_last_Java_frame()) { if (has_last_Java_frame()) {
@ -2830,7 +2853,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
{ TraceTime timer("Start VMThread", TRACETIME_LOG(Info, startuptime)); { TraceTime timer("Start VMThread", TRACETIME_LOG(Info, startuptime));
VMThread::create(); VMThread::create();
Thread* vmthread = VMThread::vm_thread(); VMThread* vmthread = VMThread::vm_thread();
if (!os::create_thread(vmthread, os::vm_thread)) { if (!os::create_thread(vmthread, os::vm_thread)) {
vm_exit_during_initialization("Cannot create VM thread. " vm_exit_during_initialization("Cannot create VM thread. "
@ -2842,7 +2865,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
{ {
MonitorLocker ml(Notify_lock); MonitorLocker ml(Notify_lock);
os::start_thread(vmthread); os::start_thread(vmthread);
while (vmthread->active_handles() == NULL) { while (!vmthread->is_running()) {
ml.wait(); ml.wait();
} }
} }

View file

@ -238,12 +238,6 @@ class Thread: public ThreadShadow {
#endif #endif
private: private:
// Active_handles points to a block of handles
JNIHandleBlock* _active_handles;
// One-element thread local free list
JNIHandleBlock* _free_handle_block;
// Point to the last handle mark // Point to the last handle mark
HandleMark* _last_handle_mark; HandleMark* _last_handle_mark;
@ -416,12 +410,6 @@ class Thread: public ThreadShadow {
OSThread* osthread() const { return _osthread; } OSThread* osthread() const { return _osthread; }
void set_osthread(OSThread* thread) { _osthread = thread; } void set_osthread(OSThread* thread) { _osthread = thread; }
// JNI handle support
JNIHandleBlock* active_handles() const { return _active_handles; }
void set_active_handles(JNIHandleBlock* block) { _active_handles = block; }
JNIHandleBlock* free_handle_block() const { return _free_handle_block; }
void set_free_handle_block(JNIHandleBlock* block) { _free_handle_block = block; }
// Internal handle support // Internal handle support
HandleArea* handle_area() const { return _handle_area; } HandleArea* handle_area() const { return _handle_area; }
void set_handle_area(HandleArea* area) { _handle_area = area; } void set_handle_area(HandleArea* area) { _handle_area = area; }
@ -607,7 +595,6 @@ protected:
// Code generation // Code generation
static ByteSize exception_file_offset() { return byte_offset_of(Thread, _exception_file); } static ByteSize exception_file_offset() { return byte_offset_of(Thread, _exception_file); }
static ByteSize exception_line_offset() { return byte_offset_of(Thread, _exception_line); } static ByteSize exception_line_offset() { return byte_offset_of(Thread, _exception_line); }
static ByteSize active_handles_offset() { return byte_offset_of(Thread, _active_handles); }
static ByteSize stack_base_offset() { return byte_offset_of(Thread, _stack_base); } static ByteSize stack_base_offset() { return byte_offset_of(Thread, _stack_base); }
static ByteSize stack_size_offset() { return byte_offset_of(Thread, _stack_size); } static ByteSize stack_size_offset() { return byte_offset_of(Thread, _stack_size); }
@ -746,6 +733,13 @@ class JavaThread: public Thread {
ObjectMonitor* volatile _current_pending_monitor; // ObjectMonitor this thread is waiting to lock ObjectMonitor* volatile _current_pending_monitor; // ObjectMonitor this thread is waiting to lock
bool _current_pending_monitor_is_from_java; // locking is from Java code bool _current_pending_monitor_is_from_java; // locking is from Java code
ObjectMonitor* volatile _current_waiting_monitor; // ObjectMonitor on which this thread called Object.wait() ObjectMonitor* volatile _current_waiting_monitor; // ObjectMonitor on which this thread called Object.wait()
// Active_handles points to a block of handles
JNIHandleBlock* _active_handles;
// One-element thread local free list
JNIHandleBlock* _free_handle_block;
public: public:
volatile intptr_t _Stalled; volatile intptr_t _Stalled;
@ -773,6 +767,15 @@ class JavaThread: public Thread {
Atomic::store(&_current_waiting_monitor, monitor); Atomic::store(&_current_waiting_monitor, monitor);
} }
// JNI handle support
JNIHandleBlock* active_handles() const { return _active_handles; }
void set_active_handles(JNIHandleBlock* block) { _active_handles = block; }
JNIHandleBlock* free_handle_block() const { return _free_handle_block; }
void set_free_handle_block(JNIHandleBlock* block) { _free_handle_block = block; }
void push_jni_handle_block();
void pop_jni_handle_block();
private: private:
MonitorChunk* _monitor_chunks; // Contains the off stack monitors MonitorChunk* _monitor_chunks; // Contains the off stack monitors
// allocated during deoptimization // allocated during deoptimization
@ -1283,6 +1286,8 @@ class JavaThread: public Thread {
static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); }
static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); }
static ByteSize active_handles_offset() { return byte_offset_of(JavaThread, _active_handles); }
// StackOverflow offsets // StackOverflow offsets
static ByteSize stack_overflow_limit_offset() { static ByteSize stack_overflow_limit_offset() {
return byte_offset_of(JavaThread, _stack_overflow_state._stack_overflow_limit); return byte_offset_of(JavaThread, _stack_overflow_state._stack_overflow_limit);
@ -1745,4 +1750,13 @@ class UnlockFlagSaver {
} }
}; };
class JNIHandleMark : public StackObj {
JavaThread* _thread;
public:
JNIHandleMark(JavaThread* thread) : _thread(thread) {
thread->push_jni_handle_block();
}
~JNIHandleMark() { _thread->pop_jni_handle_block(); }
};
#endif // SHARE_RUNTIME_THREAD_HPP #endif // SHARE_RUNTIME_THREAD_HPP

View file

@ -704,7 +704,6 @@
nonstatic_field(ThreadShadow, _pending_exception, oop) \ nonstatic_field(ThreadShadow, _pending_exception, oop) \
nonstatic_field(ThreadShadow, _exception_file, const char*) \ nonstatic_field(ThreadShadow, _exception_file, const char*) \
nonstatic_field(ThreadShadow, _exception_line, int) \ nonstatic_field(ThreadShadow, _exception_line, int) \
nonstatic_field(Thread, _active_handles, JNIHandleBlock*) \
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
nonstatic_field(Thread, _allocated_bytes, jlong) \ nonstatic_field(Thread, _allocated_bytes, jlong) \
nonstatic_field(NamedThread, _name, char*) \ nonstatic_field(NamedThread, _name, char*) \
@ -728,6 +727,7 @@
nonstatic_field(JavaThread, _stack_size, size_t) \ nonstatic_field(JavaThread, _stack_size, size_t) \
nonstatic_field(JavaThread, _vframe_array_head, vframeArray*) \ nonstatic_field(JavaThread, _vframe_array_head, vframeArray*) \
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \ nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
nonstatic_field(JavaThread, _active_handles, JNIHandleBlock*) \
volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \ volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \
nonstatic_field(Thread, _resource_area, ResourceArea*) \ nonstatic_field(Thread, _resource_area, ResourceArea*) \
nonstatic_field(CompilerThread, _env, ciEnv*) \ nonstatic_field(CompilerThread, _env, ciEnv*) \

View file

@ -139,7 +139,7 @@ void VMThread::create() {
} }
} }
VMThread::VMThread() : NamedThread() { VMThread::VMThread() : NamedThread(), _is_running(false) {
set_name("VM Thread"); set_name("VM Thread");
} }
@ -152,10 +152,10 @@ static VM_None halt_op("Halt");
void VMThread::run() { void VMThread::run() {
assert(this == vm_thread(), "check"); assert(this == vm_thread(), "check");
// Notify_lock wait checks on active_handles() to rewait in // Notify_lock wait checks on is_running() to rewait in
// case of spurious wakeup, it should wait on the last // case of spurious wakeup, it should wait on the last
// value set prior to the notify // value set prior to the notify
this->set_active_handles(JNIHandleBlock::allocate_block()); Atomic::store(&_is_running, true);
{ {
MutexLocker ml(Notify_lock); MutexLocker ml(Notify_lock);

View file

@ -25,6 +25,7 @@
#ifndef SHARE_RUNTIME_VMTHREAD_HPP #ifndef SHARE_RUNTIME_VMTHREAD_HPP
#define SHARE_RUNTIME_VMTHREAD_HPP #define SHARE_RUNTIME_VMTHREAD_HPP
#include "runtime/atomic.hpp"
#include "runtime/perfDataTypes.hpp" #include "runtime/perfDataTypes.hpp"
#include "runtime/nonJavaThread.hpp" #include "runtime/nonJavaThread.hpp"
#include "runtime/thread.hpp" #include "runtime/thread.hpp"
@ -59,6 +60,8 @@ public:
class VMThread: public NamedThread { class VMThread: public NamedThread {
private: private:
volatile bool _is_running;
static ThreadPriority _current_priority; static ThreadPriority _current_priority;
static bool _should_terminate; static bool _should_terminate;
@ -84,6 +87,7 @@ class VMThread: public NamedThread {
guarantee(false, "VMThread deletion must fix the race with VM termination"); guarantee(false, "VMThread deletion must fix the race with VM termination");
} }
bool is_running() const { return Atomic::load(&_is_running); }
// Tester // Tester
bool is_VM_thread() const { return true; } bool is_VM_thread() const { return true; }

View file

@ -52,6 +52,7 @@ public class JavaThread extends Thread {
private static AddressField stackBaseField; private static AddressField stackBaseField;
private static CIntegerField stackSizeField; private static CIntegerField stackSizeField;
private static CIntegerField terminatedField; private static CIntegerField terminatedField;
private static AddressField activeHandlesField;
private static JavaThreadPDAccess access; private static JavaThreadPDAccess access;
@ -95,6 +96,7 @@ public class JavaThread extends Thread {
stackBaseField = type.getAddressField("_stack_base"); stackBaseField = type.getAddressField("_stack_base");
stackSizeField = type.getCIntegerField("_stack_size"); stackSizeField = type.getCIntegerField("_stack_size");
terminatedField = type.getCIntegerField("_terminated"); terminatedField = type.getCIntegerField("_terminated");
activeHandlesField = type.getAddressField("_active_handles");
UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue(); UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue();
NEW = db.lookupIntConstant("_thread_new").intValue(); NEW = db.lookupIntConstant("_thread_new").intValue();
@ -409,6 +411,14 @@ public class JavaThread extends Thread {
return null; return null;
} }
public JNIHandleBlock activeHandles() {
Address a = activeHandlesField.getAddress(addr);
if (a == null) {
return null;
}
return new JNIHandleBlock(a);
}
public void printInfoOn(PrintStream tty) { public void printInfoOn(PrintStream tty) {
tty.println("State: " + getThreadState().toString()); tty.println("State: " + getThreadState().toString());

View file

@ -37,7 +37,6 @@ public class Thread extends VMObject {
// Thread::SuspendFlags enum constants // Thread::SuspendFlags enum constants
private static int HAS_ASYNC_EXCEPTION; private static int HAS_ASYNC_EXCEPTION;
private static AddressField activeHandlesField;
private static AddressField currentPendingMonitorField; private static AddressField currentPendingMonitorField;
private static AddressField currentWaitingMonitorField; private static AddressField currentWaitingMonitorField;
@ -59,7 +58,6 @@ public class Thread extends VMObject {
HAS_ASYNC_EXCEPTION = db.lookupIntConstant("JavaThread::_has_async_exception").intValue(); HAS_ASYNC_EXCEPTION = db.lookupIntConstant("JavaThread::_has_async_exception").intValue();
tlabFieldOffset = typeThread.getField("_tlab").getOffset(); tlabFieldOffset = typeThread.getField("_tlab").getOffset();
activeHandlesField = typeThread.getAddressField("_active_handles");
currentPendingMonitorField = typeJavaThread.getAddressField("_current_pending_monitor"); currentPendingMonitorField = typeJavaThread.getAddressField("_current_pending_monitor");
currentWaitingMonitorField = typeJavaThread.getAddressField("_current_waiting_monitor"); currentWaitingMonitorField = typeJavaThread.getAddressField("_current_waiting_monitor");
allocatedBytesField = typeThread.getJLongField("_allocated_bytes"); allocatedBytesField = typeThread.getJLongField("_allocated_bytes");
@ -81,14 +79,6 @@ public class Thread extends VMObject {
return new ThreadLocalAllocBuffer(addr.addOffsetTo(tlabFieldOffset)); return new ThreadLocalAllocBuffer(addr.addOffsetTo(tlabFieldOffset));
} }
public JNIHandleBlock activeHandles() {
Address a = activeHandlesField.getAddress(addr);
if (a == null) {
return null;
}
return new JNIHandleBlock(a);
}
public long allocatedBytes() { public long allocatedBytes() {
return allocatedBytesField.getValue(addr); return allocatedBytesField.getValue(addr);
} }