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 }