6642881: Improve performance of Class.getClassLoader()
Summary: Add classLoader to java/lang/Class instance for fast access
Reviewed-by: alanb, lfoltan, rriggs, vlivanov, twisti, jfranck
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Jun 19 14:49:33 2014 -0400
@@ -4139,8 +4139,8 @@
}
// Allocate mirror and initialize static fields
- java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle));
-
+ java_lang_Class::create_mirror(this_klass, class_loader, protection_domain,
+ CHECK_(nullHandle));
// Generate any default methods - default methods are interface methods
// that have a default implementation. This is new with Lambda project.
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Jun 19 14:49:33 2014 -0400
@@ -558,7 +558,7 @@
}
}
}
- create_mirror(k, Handle(NULL), CHECK);
+ create_mirror(k, Handle(NULL), Handle(NULL), CHECK);
}
void java_lang_Class::initialize_mirror_fields(KlassHandle k,
@@ -578,7 +578,8 @@
InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, mirror, CHECK);
}
-void java_lang_Class::create_mirror(KlassHandle k, Handle protection_domain, TRAPS) {
+void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
+ Handle protection_domain, TRAPS) {
assert(k->java_mirror() == NULL, "should only assign mirror once");
// Use this moment of initialization to cache modifier_flags also,
// to support Class.getModifiers(). Instance classes recalculate
@@ -633,6 +634,9 @@
}
}
+ // set the classLoader field in the java_lang_Class instance
+ set_class_loader(mirror(), class_loader());
+
// Setup indirection from klass->mirror last
// after any exceptions can happen during allocations.
if (!k.is_null()) {
@@ -694,6 +698,18 @@
}
+void java_lang_Class::set_class_loader(oop java_class, oop loader) {
+ // jdk7 runs Queens in bootstrapping and jdk8-9 has no coordinated pushes yet.
+ if (_class_loader_offset != 0) {
+ java_class->obj_field_put(_class_loader_offset, loader);
+ }
+}
+
+oop java_lang_Class::class_loader(oop java_class) {
+ assert(_class_loader_offset != 0, "must be set");
+ return java_class->obj_field(_class_loader_offset);
+}
+
oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
// This should be improved by adding a field at the Java level or by
// introducing a new VM klass (see comment in ClassFileParser)
@@ -853,6 +869,12 @@
compute_optional_offset(classRedefinedCount_offset,
klass_oop, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
+ // Needs to be optional because the old build runs Queens during bootstrapping
+ // and jdk8-9 doesn't have coordinated pushes yet.
+ compute_optional_offset(_class_loader_offset,
+ klass_oop, vmSymbols::classLoader_name(),
+ vmSymbols::classloader_signature());
+
CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
@@ -3073,6 +3095,7 @@
int java_lang_Class::_array_klass_offset;
int java_lang_Class::_oop_size_offset;
int java_lang_Class::_static_oop_field_count_offset;
+int java_lang_Class::_class_loader_offset;
int java_lang_Class::_protection_domain_offset;
int java_lang_Class::_init_lock_offset;
int java_lang_Class::_signers_offset;
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Jun 19 14:49:33 2014 -0400
@@ -240,19 +240,23 @@
static int _protection_domain_offset;
static int _init_lock_offset;
static int _signers_offset;
+ static int _class_loader_offset;
static bool offsets_computed;
static int classRedefinedCount_offset;
+
static GrowableArray<Klass*>* _fixup_mirror_list;
static void set_init_lock(oop java_class, oop init_lock);
static void set_protection_domain(oop java_class, oop protection_domain);
+ static void set_class_loader(oop java_class, oop class_loader);
static void initialize_mirror_fields(KlassHandle k, Handle mirror, Handle protection_domain, TRAPS);
public:
static void compute_offsets();
// Instance creation
- static void create_mirror(KlassHandle k, Handle protection_domain, TRAPS);
+ static void create_mirror(KlassHandle k, Handle class_loader,
+ Handle protection_domain, TRAPS);
static void fixup_mirror(KlassHandle k, TRAPS);
static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
// Conversion
@@ -290,6 +294,8 @@
static objArrayOop signers(oop java_class);
static void set_signers(oop java_class, objArrayOop signers);
+ static oop class_loader(oop java_class);
+
static int oop_size(oop java_class);
static void set_oop_size(oop java_class, int size);
static int static_oop_field_count(oop java_class);
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Jun 19 14:49:33 2014 -0400
@@ -572,6 +572,7 @@
template(serializePropertiesToByteArray_signature, "()[B") \
template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
template(classRedefinedCount_name, "classRedefinedCount") \
+ template(classLoader_name, "classLoader") \
\
/* trace signatures */ \
TRACE_TEMPLATES(template) \
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Thu Jun 19 14:49:33 2014 -0400
@@ -93,7 +93,7 @@
ResourceMark rm(THREAD);
k->initialize_supers(super_klass(), CHECK);
k->vtable()->initialize_vtable(false, CHECK);
- java_lang_Class::create_mirror(k, Handle(NULL), CHECK);
+ java_lang_Class::create_mirror(k, Handle(NULL), Handle(NULL), CHECK);
}
GrowableArray<Klass*>* ArrayKlass::compute_secondary_supers(int num_extra_slots) {
--- a/hotspot/src/share/vm/oops/klass.cpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/oops/klass.cpp Thu Jun 19 14:49:33 2014 -0400
@@ -508,7 +508,7 @@
// Only recreate it if not present. A previous attempt to restore may have
// gotten an OOM later but keep the mirror if it was created.
if (java_mirror() == NULL) {
- java_lang_Class::create_mirror(this, Handle(NULL), CHECK);
+ java_lang_Class::create_mirror(this, Handle(NULL), Handle(NULL), CHECK);
}
}
--- a/hotspot/src/share/vm/prims/unsafe.cpp Thu Jun 19 11:16:10 2014 -0400
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Thu Jun 19 14:49:33 2014 -0400
@@ -891,6 +891,14 @@
}
UNSAFE_END
+static jobject get_class_loader(JNIEnv* env, jclass cls) {
+ if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) {
+ return NULL;
+ }
+ Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls));
+ oop loader = k->class_loader();
+ return JNIHandles::make_local(env, loader);
+}
UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring name, jbyteArray data, int offset, int length))
UnsafeWrapper("Unsafe_DefineClass");
@@ -899,7 +907,7 @@
int depthFromDefineClass0 = 1;
jclass caller = JVM_GetCallerClass(env, depthFromDefineClass0);
- jobject loader = (caller == NULL) ? NULL : JVM_GetClassLoader(env, caller);
+ jobject loader = (caller == NULL) ? NULL : get_class_loader(env, caller);
jobject pd = (caller == NULL) ? NULL : JVM_GetProtectionDomain(env, caller);
return Unsafe_DefineClass_impl(env, name, data, offset, length, loader, pd);