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*.
get_string_from_cp_with_checks(const InstanceKlass * k,int cpi)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
classname_matches_prefix(const Klass * k,const char * 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.
is_generated_method_accessor(const InstanceKlass * k)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.
is_generated_constructor_accessor(const InstanceKlass * k)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.
is_generated_method_serialization_constructor_accessor(const InstanceKlass * k)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
get_target_class_name(const InstanceKlass * k)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
get_target_method_name(const InstanceKlass * k)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
get_target_method_signature(const InstanceKlass * k)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)
is_generated_accessor(const Klass * 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 }
print_invocation_target(outputStream * out,Klass * k)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 }
164