1 /* 2 * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_CDS_CLASSLISTPARSER_HPP 26 #define SHARE_CDS_CLASSLISTPARSER_HPP 27 28 #include "utilities/exceptions.hpp" 29 #include "utilities/globalDefinitions.hpp" 30 #include "utilities/growableArray.hpp" 31 #include "utilities/istream.hpp" 32 #include "utilities/resizeableResourceHash.hpp" 33 34 class constantPoolHandle; 35 class Thread; 36 37 class CDSIndyInfo { 38 GrowableArray<const char*>* _items; 39 public: 40 CDSIndyInfo() : _items(nullptr) {} 41 void add_item(const char* item) { 42 if (_items == nullptr) { 43 _items = new GrowableArray<const char*>(9); 44 } 45 assert(_items != nullptr, "sanity"); 46 _items->append(item); 47 } 48 void add_ref_kind(int ref_kind) { 49 switch (ref_kind) { 50 case JVM_REF_getField : _items->append("REF_getField"); break; 51 case JVM_REF_getStatic : _items->append("REF_getStatic"); break; 52 case JVM_REF_putField : _items->append("REF_putField"); break; 53 case JVM_REF_putStatic : _items->append("REF_putStatic"); break; 54 case JVM_REF_invokeVirtual : _items->append("REF_invokeVirtual"); break; 55 case JVM_REF_invokeStatic : _items->append("REF_invokeStatic"); break; 56 case JVM_REF_invokeSpecial : _items->append("REF_invokeSpecial"); break; 57 case JVM_REF_newInvokeSpecial : _items->append("REF_newInvokeSpecial"); break; 58 case JVM_REF_invokeInterface : _items->append("REF_invokeInterface"); break; 59 default : ShouldNotReachHere(); 60 } 61 } 62 GrowableArray<const char*>* items() { 63 return _items; 64 } 65 }; 66 67 class ClassListParser : public StackObj { 68 static const char* CONSTANT_POOL_TAG; 69 static const char* LAMBDA_FORM_TAG; 70 static const char* LAMBDA_PROXY_TAG; 71 72 public: 73 enum ParseMode { 74 _parse_all, 75 _parse_lambda_forms_invokers_only, 76 }; 77 78 private: 79 // Must be C_HEAP allocated -- we don't want nested resource allocations. 80 typedef ResizeableResourceHashtable<int, InstanceKlass*, 81 AnyObj::C_HEAP, mtClassShared> ID2KlassTable; 82 83 enum { 84 _unspecified = -999, 85 }; 86 87 // Use a small initial size in debug build to test resizing logic 88 static const int INITIAL_TABLE_SIZE = DEBUG_ONLY(17) NOT_DEBUG(1987); 89 static const int MAX_TABLE_SIZE = 61333; 90 static volatile Thread* _parsing_thread; // the thread that created _instance 91 static ClassListParser* _instance; // the singleton. 92 const char* _classlist_file; 93 94 ID2KlassTable _id2klass_table; 95 96 FileInput _file_input; 97 inputStream _input_stream; 98 char* _line; // The buffer that holds the current line. Some characters in 99 // the buffer may be overwritten by '\0' during parsing. 100 int _line_len; // Original length of the input line. 101 const char* _class_name; 102 GrowableArray<const char*>* _indy_items; // items related to invoke dynamic for archiving lambda proxy classes 103 int _id; 104 int _super; 105 GrowableArray<int>* _interfaces; 106 bool _interfaces_specified; 107 const char* _source; 108 ParseMode _parse_mode; 109 110 bool parse_int_option(const char* option_name, int* value); 111 bool parse_uint_option(const char* option_name, int* value); 112 InstanceKlass* load_class_from_source(Symbol* class_name, TRAPS); 113 ID2KlassTable* id2klass_table() { 114 return &_id2klass_table; 115 } 116 InstanceKlass* lookup_class_by_id(int id); 117 void print_specified_interfaces(); 118 void print_actual_interfaces(InstanceKlass *ik); 119 bool is_matching_cp_entry(const constantPoolHandle &pool, int cp_index, TRAPS); 120 121 InstanceKlass* find_builtin_class_helper(JavaThread* current, Symbol* class_name_symbol, oop class_loader_oop); 122 InstanceKlass* find_builtin_class(JavaThread* current, const char* class_name); 123 124 void resolve_indy(JavaThread* current, Symbol* class_name_symbol); 125 void resolve_indy_impl(Symbol* class_name_symbol, TRAPS); 126 void clean_up_input_line(); 127 void read_class_name_and_attributes(); 128 void parse_class_name_and_attributes(TRAPS); 129 Klass* load_current_class(Symbol* class_name_symbol, TRAPS); 130 void parse_constant_pool_tag(); 131 132 size_t lineno() { return _input_stream.lineno(); } 133 FILE* do_open(const char* file); 134 ClassListParser(const char* file, ParseMode _parse_mode); 135 ~ClassListParser(); 136 void print_diagnostic_info(outputStream* st, const char* msg, va_list ap) ATTRIBUTE_PRINTF(3, 0); 137 void print_diagnostic_info(outputStream* st, const char* msg, ...) ATTRIBUTE_PRINTF(3, 0); 138 void constant_pool_resolution_warning(const char* msg, ...) ATTRIBUTE_PRINTF(2, 0); 139 void error(const char* msg, ...) ATTRIBUTE_PRINTF(2, 0); 140 objArrayOop get_specified_interfaces(TRAPS); 141 142 public: 143 static void parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS); 144 145 static bool is_parsing_thread(); 146 static ClassListParser* instance() { 147 assert(is_parsing_thread(), "call this only in the thread that created ClassListParsing::_instance"); 148 assert(_instance != nullptr, "must be"); 149 return _instance; 150 } 151 static const char* lambda_proxy_tag() { 152 return LAMBDA_PROXY_TAG; 153 } 154 static const char* lambda_form_tag() { 155 return LAMBDA_FORM_TAG; 156 } 157 158 void parse(TRAPS); 159 void split_tokens_by_whitespace(int offset, GrowableArray<const char*>* items); 160 int split_at_tag_from_line(); 161 void parse_at_tags(TRAPS); 162 char* _token; 163 void parse_int(int* value); 164 void parse_uint(int* value); 165 bool try_parse_uint(int* value); 166 bool skip_token(const char* option_name); 167 void skip_whitespaces(); 168 void skip_non_whitespaces(); 169 170 bool parse_lambda_forms_invokers_only() { 171 return _parse_mode == _parse_lambda_forms_invokers_only; 172 } 173 bool is_id_specified() { 174 return _id != _unspecified; 175 } 176 bool is_super_specified() { 177 return _super != _unspecified; 178 } 179 bool are_interfaces_specified() { 180 return _interfaces->length() > 0; 181 } 182 int id() { 183 assert(is_id_specified(), "do not query unspecified id"); 184 return _id; 185 } 186 int super() { 187 assert(is_super_specified(), "do not query unspecified super"); 188 return _super; 189 } 190 void check_already_loaded(const char* which, int id) { 191 if (!id2klass_table()->contains(id)) { 192 error("%s id %d is not yet loaded", which, id); 193 } 194 } 195 void check_class_name(const char* class_name); 196 197 const char* current_class_name() { 198 return _class_name; 199 } 200 201 bool is_loading_from_source(); 202 static void populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS); 203 }; 204 #endif // SHARE_CDS_CLASSLISTPARSER_HPP