--- old/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp 2018-05-19 07:14:07.440398821 +0200 +++ new/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp 2018-05-19 07:14:07.296397647 +0200 @@ -37,6 +37,82 @@ namespace metaspace { +bool PrintMetaspaceInfoKlassClosure::print_reflection_invocation_target(outputStream* out, InstanceKlass* magic_accessor_impl_class) { + assert(magic_accessor_impl_class->is_subclass_of(SystemDictionary::reflect_ConstructorAccessorImpl_klass()) || + magic_accessor_impl_class->is_subclass_of(SystemDictionary::reflect_MethodAccessorImpl_klass()), "Must be."); + + // We extract target class name, method name and sig from the constant pool of the Accessor class. + // This is an excerpt of the Constant pool (see jdk/internal/reflect/MethodAccessorGenerator.java:) + + // (^ = Only present if generating SerializationConstructorAccessor) + // 1 [UTF-8] [This class's name] + // 2 [CONSTANT_Class_info] for above + // 3 [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" + // 4 [CONSTANT_Class_info] for above + // 5 [UTF-8] [Target class's name] + // 6 [CONSTANT_Class_info] for above + // 7^ [UTF-8] [Serialization: Class's name in which to invoke constructor] + // 8^ [CONSTANT_Class_info] for above + // 9 [UTF-8] target method or constructor name + // 10 [UTF-8] target method or constructor signature + + // Note that these strings are found at slightly different slots depending on the class type: + // - MethodAccessorImpl, ConstructoreAccessorImpl: slots 5, 7 and 8. + // - SerializationConstructorAccessorImpl: slots 5, 9 and 10. + // Unfortunately SerializationConstructorAccessorImpl is a child of ConstructoreAccessorImpl and there + // is no easy way to tell them apart. So we examine parent class name. + const int parent_class_name_cpi = 3; + const char* parent_class_name = NULL; + + const int target_class_name_cpi = 5; + const char* target_class_name = NULL; + + int target_method_name_cpi = -1; + const char* target_method_name = NULL; + + int target_method_signature_cpi = -1; + const char* target_method_signature = NULL; + + ConstantPool* const cp = magic_accessor_impl_class->constants(); + if (!cp->tag_at(parent_class_name_cpi).is_utf8()) { + return false; + } + + parent_class_name = cp->symbol_at(parent_class_name_cpi)->as_C_string(); + + if (strcmp("jdk/internal/reflect/SerializationConstructorAccessorImpl", parent_class_name) == 0) { + target_method_name_cpi = 9; + target_method_signature_cpi = 10; + } else if (strcmp("jdk/internal/reflect/ConstructorAccessorImpl", parent_class_name) == 0 || + strcmp("jdk/internal/reflect/MethodAccessorImpl", parent_class_name) == 0) { + target_method_name_cpi = 7; + target_method_signature_cpi = 8; + } else { + return false; + } + + assert(target_method_name_cpi != -1 && target_method_signature_cpi != -1, "Must be"); + if (target_method_name_cpi == -1 || target_method_signature_cpi == -1) { + return false; // behave well in release. + } + + if (!cp->tag_at(target_class_name_cpi).is_utf8() || !cp->tag_at(target_method_name_cpi).is_utf8() || + !cp->tag_at(target_method_signature_cpi).is_utf8()) { + return false; + } + + target_class_name = cp->symbol_at(target_class_name_cpi)->as_C_string(); + target_method_name = cp->symbol_at(target_method_name_cpi)->as_C_string(); + target_method_signature = cp->symbol_at(target_method_signature_cpi)->as_C_string(); + + if (target_class_name == NULL || target_method_name == NULL || target_method_signature == NULL) { + return false; + } + out->print("%s::%s %s", target_class_name, target_method_name, target_method_signature); + + return true; +} + PrintMetaspaceInfoKlassClosure::PrintMetaspaceInfoKlassClosure(outputStream* out, bool do_print) : _out(out), _do_print(do_print) , _num_classes(0), _num_instance_classes(0), _num_array_classes(0) { @@ -54,6 +130,21 @@ _out->print(UINTX_FORMAT_W(4) ": ", _num_classes); ResourceMark rm; _out->print("%s", k->external_name()); + + if (k->is_instance_klass()) { + // For descendants of {Method|ConstructorAccessor}Impl, print target class and method/ctor + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->is_initialized()) { + if (ik->is_subclass_of(SystemDictionary::reflect_ConstructorAccessorImpl_klass()) || + ik->is_subclass_of(SystemDictionary::reflect_MethodAccessorImpl_klass())) { + _out->print(" (invokes: "); + if (!print_reflection_invocation_target(_out, ik)) { + _out->print("?"); + } + _out->print(")"); + } + } + } } }