1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018, SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 #include "classfile/systemDictionary.hpp" 28 #include "memory/resourceArea.hpp" 29 #include "oops/reflectionAccessorImplKlassHelper.hpp" 30 #include "utilities/constantTag.hpp" 31 #include "utilities/debug.hpp" 32 #include "utilities/globalDefinitions.hpp" 33 34 // This code extracts name of target class, method and signature from the constant pool of a class 35 // assumed to be of type jdk/internal/reflect/Generated{SerializationConstructor|Constructor|Method}AccessorXXX. 36 // Since this may be affected by bitrot if these classes change, extra care is taken to make the 37 // release build of this coding robust. 38 39 // We extract target class name, method name and sig from the constant pool of the Accessor class. 40 // This is an excerpt of the Constant pool (see jdk/internal/reflect/MethodAccessorGenerator.java:) 41 42 // (^ = Only present if generating SerializationConstructorAccessor) 43 // 1 [UTF-8] [This class's name] 44 // 2 [CONSTANT_Class_info] for above 45 // 3 [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" 46 // 4 [CONSTANT_Class_info] for above 47 // 5 [UTF-8] [Target class's name] 48 // 6 [CONSTANT_Class_info] for above 49 // 7^ [UTF-8] [Serialization: Class's name in which to invoke constructor] 50 // 8^ [CONSTANT_Class_info] for above 51 // 9 [UTF-8] target method or constructor name 52 // 10 [UTF-8] target method or constructor signature 53 54 // Note that these strings are found at slightly different slots depending on the class type: 55 // - MethodAccessorImpl, ConstructoreAccessorImpl: slots 5, 7 and 8. 56 // - SerializationConstructorAccessorImpl: slots 5, 9 and 10. 57 // Unfortunately SerializationConstructorAccessorImpl is a child of ConstructoreAccessorImpl and there 58 // is no easy way to tell them apart. So we examine parent class name. 59 60 enum cpi_slots { 61 cpi_slot_parent_class_name = 3, 62 cpi_slot_target_class_name = 5, 63 cpi_slot_target_method_name = 7, 64 cpi_slot_target_method_name_sca = 9, // SerializationConstructorAccessor case, see above 65 cpi_slot_target_method_sig = 8, 66 cpi_slot_target_method_sig_sca = 10 // SerializationConstructorAccessor case, see above 67 }; 68 69 // Returns a string, resource-area allocated, from an UTF8 slot in the constant pool in the 70 // given Klass*. 71 static const char* get_string_from_cp_with_checks(const InstanceKlass* k, int cpi) { 72 const char* s = NULL; 73 const ConstantPool* const cp = k->constants(); 74 75 assert(cp != NULL, "No cp?"); 76 assert(cp->is_within_bounds(cpi), "Unexpected constant pool layout for \"%s\", child class of Generated{Method|Constructor}AccessorImplXXX" 77 " (cpi %d out of bounds for [0..%d)).", k->external_name(), cpi, cp->length()); 78 assert(cp->tag_at(cpi).is_utf8(), "Unexpected constant pool layout for \"%s\", child class of Generated{Method|Constructor}AccessorImplXXX" 79 " (no UTF8 at cpi %d (%u)).", k->external_name(), cpi, cp->tag_at(cpi).value()); 80 81 // Be nice in release: lets not crash, just return NULL. 82 if (cp != NULL && cp->is_within_bounds(cpi) && cp->tag_at(cpi).is_utf8()) { 83 s = cp->symbol_at(cpi)->as_C_string(); 84 } 85 86 return s; 87 } 88 89 // helper, returns true if class name of given class matches a given prefix 90 static bool classname_matches_prefix(const Klass* k, const char* prefix) { 91 const char* classname = k->external_name(); 92 if (classname != NULL) { 93 if (::strncmp(classname, prefix, strlen(prefix)) == 0) { 94 return true; 95 } 96 } 97 return false; 98 } 99 100 // Returns true if k is of type jdk/internal/reflect/GeneratedMethodAccessorXXX. 101 bool ReflectionAccessorImplKlassHelper::is_generated_method_accessor(const InstanceKlass* k) { 102 return k->super() == SystemDictionary::reflect_MethodAccessorImpl_klass() && 103 classname_matches_prefix(k, "jdk.internal.reflect.GeneratedMethodAccessor"); 104 } 105 106 // Returns true if k is of type jdk/internal/reflect/GeneratedConstructorAccessorXXX. 107 bool ReflectionAccessorImplKlassHelper::is_generated_constructor_accessor(const InstanceKlass* k) { 108 return k->super() == SystemDictionary::reflect_ConstructorAccessorImpl_klass() && 109 classname_matches_prefix(k, "jdk.internal.reflect.GeneratedConstructorAccessor"); 110 } 111 112 // Returns true if k is of type jdk/internal/reflect/GeneratedSerializationConstructorAccessorXXX. 113 bool ReflectionAccessorImplKlassHelper::is_generated_method_serialization_constructor_accessor(const InstanceKlass* k) { 114 // GeneratedSerializationConstructorAccessor is not a direct subclass of ConstructorAccessorImpl 115 const Klass* sk = k->super(); 116 if (sk != NULL && sk->super() == SystemDictionary::reflect_ConstructorAccessorImpl_klass() && 117 classname_matches_prefix(k, "jdk.internal.reflect.GeneratedSerializationConstructorAccessor")) { 118 return true; 119 } 120 return false; 121 } 122 123 const char* ReflectionAccessorImplKlassHelper::get_target_class_name(const InstanceKlass* k) { 124 return get_string_from_cp_with_checks(k, cpi_slot_target_class_name); 125 } 126 127 const char* ReflectionAccessorImplKlassHelper::get_target_method_name(const InstanceKlass* k) { 128 const int target_method_name_cpi = 129 is_generated_method_serialization_constructor_accessor(k) ? cpi_slot_target_method_name_sca : cpi_slot_target_method_name; 130 return get_string_from_cp_with_checks(k, target_method_name_cpi); 131 } 132 133 const char* ReflectionAccessorImplKlassHelper::get_target_method_signature(const InstanceKlass* k) { 134 const int target_method_name_cpi = 135 is_generated_method_serialization_constructor_accessor(k) ? cpi_slot_target_method_sig_sca : cpi_slot_target_method_sig; 136 return get_string_from_cp_with_checks(k, target_method_name_cpi); 137 } 138 139 // Returns true if this is either one of jdk/internal/reflect/Generated{SerializationConstructor|Constructor|Method}AccessorXXX 140 // and it is safe to call print_invocation_target(k) 141 bool ReflectionAccessorImplKlassHelper::is_generated_accessor(const Klass* k) { 142 if (k != NULL && k->is_instance_klass()) { 143 const InstanceKlass* ik = InstanceKlass::cast(k); 144 if (ik->is_initialized()) { 145 return is_generated_method_accessor(ik) || 146 is_generated_constructor_accessor(ik) || 147 is_generated_method_serialization_constructor_accessor(ik); 148 } 149 } 150 return false; 151 } 152 void ReflectionAccessorImplKlassHelper::print_invocation_target(outputStream* out, Klass* k) { 153 assert(ReflectionAccessorImplKlassHelper::is_generated_accessor(k), "Invariant"); 154 InstanceKlass* ik = InstanceKlass::cast(k); 155 ResourceMark rm; 156 const char* target_class_name = ReflectionAccessorImplKlassHelper::get_target_class_name(ik); 157 const char* target_method_name = ReflectionAccessorImplKlassHelper::get_target_method_name(ik); 158 const char* target_method_signature = ReflectionAccessorImplKlassHelper::get_target_method_signature(ik); 159 out->print("%s::%s %s", 160 target_class_name != NULL ? target_class_name : "?", 161 target_method_name != NULL ? target_method_name : "?", 162 target_method_signature != NULL ? target_method_signature : "?"); 163 }