6964458: Reimplement class meta-data storage to use native memory

Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes

Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
This commit is contained in:
Jon Masamitsu 2012-09-01 13:25:18 -04:00 committed by Coleen Phillimore
parent 36eee7c8c8
commit 5c58d27aac
853 changed files with 26124 additions and 82956 deletions

View file

@ -34,6 +34,7 @@
#include "interpreter/oopMapCache.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.inline.hpp"
#include "oops/instanceKlass.hpp"
@ -219,6 +220,7 @@ Thread::Thread() {
set_osthread(NULL);
set_resource_area(new (mtThread)ResourceArea());
set_handle_area(new (mtThread) HandleArea(NULL));
set_metadata_handles(new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(300, true));
set_active_handles(NULL);
set_free_handle_block(NULL);
set_last_handle_mark(NULL);
@ -346,6 +348,7 @@ Thread::~Thread() {
ParkEvent::Release (_MuxEvent) ; _MuxEvent = NULL ;
delete handle_area();
delete metadata_handles();
// osthread() can be NULL, if creation of thread failed.
if (osthread() != NULL) os::free_thread(osthread());
@ -817,6 +820,14 @@ void Thread::nmethods_do(CodeBlobClosure* cf) {
// no nmethods in a generic thread...
}
void Thread::metadata_do(void f(Metadata*)) {
if (metadata_handles() != NULL) {
for (int i = 0; i< metadata_handles()->length(); i++) {
f(metadata_handles()->at(i));
}
}
}
void Thread::print_on(outputStream* st) const {
// get_priority assumes osthread initialized
if (osthread() != NULL) {
@ -916,6 +927,8 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) {
bool Thread::is_in_stack(address adr) const {
assert(Thread::current() == this, "is_in_stack can only be called from current thread");
address end = os::current_stack_pointer();
// Allow non Java threads to call this without stack_base
if (_stack_base == NULL) return true;
if (stack_base() >= adr && adr >= end) return true;
return false;
@ -937,14 +950,14 @@ bool Thread::set_as_starting_thread() {
}
static void initialize_class(Symbol* class_name, TRAPS) {
klassOop klass = SystemDictionary::resolve_or_fail(class_name, true, CHECK);
instanceKlass::cast(klass)->initialize(CHECK);
Klass* klass = SystemDictionary::resolve_or_fail(class_name, true, CHECK);
InstanceKlass::cast(klass)->initialize(CHECK);
}
// Creates the initial ThreadGroup
static Handle create_initial_thread_group(TRAPS) {
klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ThreadGroup(), true, CHECK_NH);
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ThreadGroup(), true, CHECK_NH);
instanceKlassHandle klass (THREAD, k);
Handle system_instance = klass->allocate_instance_handle(CHECK_NH);
@ -977,7 +990,7 @@ static Handle create_initial_thread_group(TRAPS) {
// Creates the initial Thread
static oop create_initial_thread(Handle thread_group, JavaThread* thread, TRAPS) {
klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL);
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL);
instanceKlassHandle klass (THREAD, k);
instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL);
@ -999,7 +1012,7 @@ static oop create_initial_thread(Handle thread_group, JavaThread* thread, TRAPS)
}
static void call_initializeSystemClass(TRAPS) {
klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK);
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK);
instanceKlassHandle klass (THREAD, k);
JavaValue result(T_VOID);
@ -1011,11 +1024,11 @@ char java_runtime_name[128] = "";
// extract the JRE name from sun.misc.Version.java_runtime_name
static const char* get_java_runtime_name(TRAPS) {
klassOop k = SystemDictionary::find(vmSymbols::sun_misc_Version(),
Klass* k = SystemDictionary::find(vmSymbols::sun_misc_Version(),
Handle(), Handle(), CHECK_AND_CLEAR_NULL);
fieldDescriptor fd;
bool found = k != NULL &&
instanceKlass::cast(k)->find_local_field(vmSymbols::java_runtime_name_name(),
InstanceKlass::cast(k)->find_local_field(vmSymbols::java_runtime_name_name(),
vmSymbols::string_signature(), &fd);
if (found) {
oop name_oop = k->java_mirror()->obj_field(fd.offset());
@ -1033,7 +1046,7 @@ static const char* get_java_runtime_name(TRAPS) {
// General purpose hook into Java code, run once when the VM is initialized.
// The Java library method itself may be changed independently from the VM.
static void call_postVMInitHook(TRAPS) {
klassOop k = SystemDictionary::PostVMInitHook_klass();
Klass* k = SystemDictionary::PostVMInitHook_klass();
instanceKlassHandle klass (THREAD, k);
if (klass.not_null()) {
JavaValue result(T_VOID);
@ -1049,7 +1062,7 @@ static void reset_vm_info_property(TRAPS) {
const char *vm_info = VM_Version::vm_info_string();
// java.lang.System class
klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK);
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK);
instanceKlassHandle klass (THREAD, k);
// setProperty arguments
@ -1074,7 +1087,7 @@ void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name, bool
assert(thread_group.not_null(), "thread group should be specified");
assert(threadObj() == NULL, "should only create Java thread object once");
klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);
instanceKlassHandle klass (THREAD, k);
instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
@ -1982,7 +1995,7 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
frame f = last_frame();
tty->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", f.pc(), f.sp());
}
tty->print_cr(" of type: %s", instanceKlass::cast(_pending_async_exception->klass())->external_name());
tty->print_cr(" of type: %s", InstanceKlass::cast(_pending_async_exception->klass())->external_name());
}
_pending_async_exception = NULL;
clear_has_async_exception();
@ -2103,10 +2116,10 @@ void JavaThread::send_thread_stop(oop java_throwable) {
if (TraceExceptions) {
ResourceMark rm;
tty->print_cr("Pending Async. exception installed of type: %s", instanceKlass::cast(_pending_async_exception->klass())->external_name());
tty->print_cr("Pending Async. exception installed of type: %s", InstanceKlass::cast(_pending_async_exception->klass())->external_name());
}
// for AbortVMOnException flag
NOT_PRODUCT(Exceptions::debug_check_abort(instanceKlass::cast(_pending_async_exception->klass())->external_name()));
NOT_PRODUCT(Exceptions::debug_check_abort(InstanceKlass::cast(_pending_async_exception->klass())->external_name()));
}
}
@ -2656,7 +2669,6 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// around using this function
f->do_oop((oop*) &_threadObj);
f->do_oop((oop*) &_vm_result);
f->do_oop((oop*) &_vm_result_2);
f->do_oop((oop*) &_exception_oop);
f->do_oop((oop*) &_pending_async_exception);
@ -2679,6 +2691,22 @@ void JavaThread::nmethods_do(CodeBlobClosure* cf) {
}
}
void JavaThread::metadata_do(void f(Metadata*)) {
Thread::metadata_do(f);
if (has_last_Java_frame()) {
// Traverse the execution stack to call f() on the methods in the stack
for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
fst.current()->metadata_do(f);
}
} else if (is_Compiler_thread()) {
// need to walk ciMetadata in current compile tasks to keep alive.
CompilerThread* ct = (CompilerThread*)this;
if (ct->env() != NULL) {
ct->env()->metadata_do(f);
}
}
}
// Printing
const char* _get_thread_state_name(JavaThreadState _thread_state) {
switch (_thread_state) {
@ -2869,7 +2897,7 @@ void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) {
Handle thread_oop(Thread::current(),
JNIHandles::resolve_non_null(jni_thread));
assert(instanceKlass::cast(thread_oop->klass())->is_linked(),
assert(InstanceKlass::cast(thread_oop->klass())->is_linked(),
"must be initialized");
set_threadObj(thread_oop());
java_lang_Thread::set_thread(thread_oop(), this);
@ -3070,7 +3098,7 @@ javaVFrame* JavaThread::last_java_vframe(RegisterMap *reg_map) {
}
klassOop JavaThread::security_get_caller_class(int depth) {
Klass* JavaThread::security_get_caller_class(int depth) {
vframeStream vfst(this);
vfst.security_get_caller_frame(depth);
if (!vfst.at_end()) {
@ -3123,6 +3151,9 @@ int Threads::_number_of_threads = 0;
int Threads::_number_of_non_daemon_threads = 0;
int Threads::_return_code = 0;
size_t JavaThread::_stack_size_at_create = 0;
#ifdef ASSERT
bool Threads::_vm_complete = false;
#endif
// All JavaThreads
#define ALL_JAVA_THREADS(X) for (JavaThread* X = _thread_list; X; X = X->next())
@ -3320,9 +3351,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// At this point, the Universe is initialized, but we have not executed
// any byte code. Now is a good time (the only time) to dump out the
// internal state of the JVM for sharing.
if (DumpSharedSpaces) {
Universe::heap()->preload_and_dump(CHECK_0);
MetaspaceShared::preload_and_dump(CHECK_0);
ShouldNotReachHere();
}
@ -3351,10 +3381,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// Forcibly initialize java/util/HashMap and mutate the private
// static final "frontCacheEnabled" field before we start creating instances
#ifdef ASSERT
klassOop tmp_k = SystemDictionary::find(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
Klass* tmp_k = SystemDictionary::find(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet");
#endif
klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
Klass* k_o = SystemDictionary::resolve_or_null(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
KlassHandle k = KlassHandle(THREAD, k_o);
guarantee(k.not_null(), "Must find java/util/HashMap");
instanceKlassHandle ik = instanceKlassHandle(THREAD, k());
@ -3369,7 +3399,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
if (UseStringCache) {
// Forcibly initialize java/lang/StringValue and mutate the private
// static final "stringCacheEnabled" field before we start creating instances
klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_lang_StringValue(), Handle(), Handle(), CHECK_0);
Klass* k_o = SystemDictionary::resolve_or_null(vmSymbols::java_lang_StringValue(), Handle(), Handle(), CHECK_0);
// Possible that StringValue isn't present: if so, silently don't break
if (k_o != NULL) {
KlassHandle k = KlassHandle(THREAD, k_o);
@ -3574,6 +3604,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
os::init_3();
create_vm_timer.end();
#ifdef ASSERT
_vm_complete = true;
#endif
return JNI_OK;
}
@ -3781,7 +3814,7 @@ void JavaThread::invoke_shutdown_hooks() {
}
EXCEPTION_MARK;
klassOop k =
Klass* k =
SystemDictionary::resolve_or_null(vmSymbols::java_lang_Shutdown(),
THREAD);
if (k != NULL) {
@ -3840,6 +3873,9 @@ void JavaThread::invoke_shutdown_hooks() {
bool Threads::destroy_vm() {
JavaThread* thread = JavaThread::current();
#ifdef ASSERT
_vm_complete = false;
#endif
// Wait until we are the last non-daemon thread to execute
{ MutexLocker nu(Threads_lock);
while (Threads::number_of_non_daemon_threads() > 1 )
@ -4100,6 +4136,12 @@ void Threads::nmethods_do(CodeBlobClosure* cf) {
VMThread::vm_thread()->nmethods_do(cf);
}
void Threads::metadata_do(void f(Metadata*)) {
ALL_JAVA_THREADS(p) {
p->metadata_do(f);
}
}
void Threads::gc_epilogue() {
ALL_JAVA_THREADS(p) {
p->gc_epilogue();