1 /* 2 * Copyright (c) 2015, 2024, 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 #define LAMBDA_PROXY_TAG "@lambda-proxy" 35 #define LAMBDA_FORM_TAG "@lambda-form-invoker" 36 37 class constantPoolHandle; 38 class Thread; 39 40 class CDSIndyInfo { 41 GrowableArray<const char*>* _items; 42 public: 43 CDSIndyInfo() : _items(nullptr) {} 44 void add_item(const char* item) { 45 if (_items == nullptr) { 46 _items = new GrowableArray<const char*>(9); 47 } 48 assert(_items != nullptr, "sanity"); 49 _items->append(item); 50 } 51 void add_ref_kind(int ref_kind) { 52 switch (ref_kind) { 53 case JVM_REF_getField : _items->append("REF_getField"); break; 54 case JVM_REF_getStatic : _items->append("REF_getStatic"); break; 55 case JVM_REF_putField : _items->append("REF_putField"); break; 56 case JVM_REF_putStatic : _items->append("REF_putStatic"); break; 57 case JVM_REF_invokeVirtual : _items->append("REF_invokeVirtual"); break; 58 case JVM_REF_invokeStatic : _items->append("REF_invokeStatic"); break; 59 case JVM_REF_invokeSpecial : _items->append("REF_invokeSpecial"); break; 60 case JVM_REF_newInvokeSpecial : _items->append("REF_newInvokeSpecial"); break; 61 case JVM_REF_invokeInterface : _items->append("REF_invokeInterface"); break; 62 default : ShouldNotReachHere(); 63 } 64 } 65 GrowableArray<const char*>* items() { 66 return _items; 67 } 68 }; 69 70 class ClassListParser : public StackObj { 71 public: 72 enum ParseMode { 73 _parse_all, 74 _parse_lambda_forms_invokers_only, 75 }; 76 77 private: 78 // Must be C_HEAP allocated -- we don't want nested resource allocations. 79 typedef ResizeableResourceHashtable<int, InstanceKlass*, 80 AnyObj::C_HEAP, mtClassShared> ID2KlassTable; 81 82 enum { 83 _unspecified = -999, 84 }; 85 86 // Use a small initial size in debug build to test resizing logic 87 static const int INITIAL_TABLE_SIZE = DEBUG_ONLY(17) NOT_DEBUG(1987); 88 static const int MAX_TABLE_SIZE = 61333; 89 static volatile Thread* _parsing_thread; // the thread that created _instance 90 static ClassListParser* _instance; // the singleton. 91 const char* _classlist_file; 92 93 ID2KlassTable _id2klass_table; 94 95 FileInput _file_input; 96 inputStream _input_stream; 97 char* _line; // The buffer that holds the current line. Some characters in 98 // the buffer may be overwritten by '\0' during parsing. 99 int _line_len; // Original length of the input line. 100 const char* _class_name; 101 GrowableArray<const char*>* _indy_items; // items related to invoke dynamic for archiving lambda proxy classes 102 int _id; 103 int _super; 104 GrowableArray<int>* _interfaces; 105 bool _interfaces_specified; 106 const char* _source; 107 ParseMode _parse_mode; 108 109 bool parse_int_option(const char* option_name, int* value); 110 bool parse_uint_option(const char* option_name, int* value); 111 InstanceKlass* load_class_from_source(Symbol* class_name, TRAPS); 112 ID2KlassTable* id2klass_table() { 113 return &_id2klass_table; 114 } 115 InstanceKlass* lookup_class_by_id(int id); 116 void print_specified_interfaces(); 117 void print_actual_interfaces(InstanceKlass *ik); 118 bool is_matching_cp_entry(const constantPoolHandle &pool, int cp_index, TRAPS); 119 120 void resolve_indy(JavaThread* current, Symbol* class_name_symbol); 121 void resolve_indy_impl(Symbol* class_name_symbol, TRAPS); 122 void clean_up_input_line(); 123 void read_class_name_and_attributes(); 124 void parse_class_name_and_attributes(TRAPS); 125 Klass* load_current_class(Symbol* class_name_symbol, TRAPS); 126 127 size_t lineno() { return _input_stream.lineno(); } 128 FILE* do_open(const char* file); 129 ClassListParser(const char* file, ParseMode _parse_mode); 130 ~ClassListParser(); 131 132 public: 133 static void parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS) { 134 ClassListParser parser(classlist_path, parse_mode); 135 parser.parse(THREAD); 136 } 137 138 static bool is_parsing_thread(); 139 static ClassListParser* instance() { 140 assert(is_parsing_thread(), "call this only in the thread that created ClassListParsing::_instance"); 141 assert(_instance != nullptr, "must be"); 142 return _instance; 143 } 144 145 void parse(TRAPS); 146 void split_tokens_by_whitespace(int offset, GrowableArray<const char*>* items); 147 int split_at_tag_from_line(); 148 void parse_at_tags(TRAPS); 149 char* _token; 150 void error(const char* msg, ...); 151 void parse_int(int* value); 152 void parse_uint(int* value); 153 bool try_parse_uint(int* value); 154 bool skip_token(const char* option_name); 155 void skip_whitespaces(); 156 void skip_non_whitespaces(); 157 158 bool parse_lambda_forms_invokers_only() { 159 return _parse_mode == _parse_lambda_forms_invokers_only; 160 } 161 bool is_id_specified() { 162 return _id != _unspecified; 163 } 164 bool is_super_specified() { 165 return _super != _unspecified; 166 } 167 bool are_interfaces_specified() { 168 return _interfaces->length() > 0; 169 } 170 int id() { 171 assert(is_id_specified(), "do not query unspecified id"); 172 return _id; 173 } 174 int super() { 175 assert(is_super_specified(), "do not query unspecified super"); 176 return _super; 177 } 178 void check_already_loaded(const char* which, int id) { 179 if (!id2klass_table()->contains(id)) { 180 error("%s id %d is not yet loaded", which, id); 181 } 182 } 183 void check_class_name(const char* class_name); 184 185 const char* current_class_name() { 186 return _class_name; 187 } 188 189 bool is_loading_from_source(); 190 191 // Look up the super or interface of the current class being loaded 192 // (in this->load_current_class()). 193 InstanceKlass* lookup_super_for_current_class(Symbol* super_name); 194 InstanceKlass* lookup_interface_for_current_class(Symbol* interface_name); 195 196 static void populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS); 197 }; 198 #endif // SHARE_CDS_CLASSLISTPARSER_HPP