1 /* 2 * Copyright (c) 1997, 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 #include "cds/cdsConfig.hpp" 26 #include "cds/serializeClosure.hpp" 27 #include "classfile/symbolTable.hpp" 28 #include "classfile/vmSymbols.hpp" 29 #include "compiler/compilerDirectives.hpp" 30 #include "jvm.h" 31 #include "memory/allocation.inline.hpp" 32 #include "memory/oopFactory.hpp" 33 #include "memory/metaspaceClosure.hpp" 34 #include "oops/oop.inline.hpp" 35 #include "runtime/handles.inline.hpp" 36 #include "runtime/signature.hpp" 37 #include "utilities/xmlstream.hpp" 38 39 40 Symbol* vmSymbols::_type_signatures[T_VOID+1] = { nullptr /*, nullptr...*/ }; 41 42 inline int compare_symbol(const Symbol* a, const Symbol* b) { 43 if (a == b) return 0; 44 // follow the natural address order: 45 return (address)a > (address)b ? +1 : -1; 46 } 47 48 static vmSymbolID vm_symbol_index[vmSymbols::number_of_symbols()]; 49 extern "C" { 50 static int compare_vmsymbol_sid(const void* void_a, const void* void_b) { 51 const Symbol* a = Symbol::vm_symbol_at(*((vmSymbolID*) void_a)); 52 const Symbol* b = Symbol::vm_symbol_at(*((vmSymbolID*) void_b)); 53 return compare_symbol(a, b); 54 } 55 } 56 57 #ifdef ASSERT 58 #define VM_SYMBOL_ENUM_NAME_BODY(name, string) #name "\0" 59 static const char* vm_symbol_enum_names = 60 VM_SYMBOLS_DO(VM_SYMBOL_ENUM_NAME_BODY, VM_ALIAS_IGNORE) 61 "\0"; 62 static const char* vm_symbol_enum_name(vmSymbolID sid) { 63 const char* string = &vm_symbol_enum_names[0]; 64 int skip = vmSymbols::as_int(sid) - vmSymbols::as_int(vmSymbolID::FIRST_SID); 65 for (; skip != 0; skip--) { 66 size_t skiplen = strlen(string); 67 if (skiplen == 0) return "<unknown>"; // overflow 68 string += skiplen+1; 69 } 70 return string; 71 } 72 #endif //ASSERT 73 74 // Put all the VM symbol strings in one place. 75 // Makes for a more compact libjvm. 76 #define VM_SYMBOL_BODY(name, string) string "\0" 77 static const char* vm_symbol_bodies = VM_SYMBOLS_DO(VM_SYMBOL_BODY, VM_ALIAS_IGNORE); 78 79 void vmSymbols::initialize() { 80 assert(SID_LIMIT <= (1<<log2_SID_LIMIT), "must fit in this bitfield"); 81 assert(SID_LIMIT*5 > (1<<log2_SID_LIMIT), "make the bitfield smaller, please"); 82 assert(vmIntrinsics::FLAG_LIMIT <= (1 << vmIntrinsics::log2_FLAG_LIMIT), "must fit in this bitfield"); 83 84 if (!CDSConfig::is_using_archive()) { 85 const char* string = &vm_symbol_bodies[0]; 86 for (auto index : EnumRange<vmSymbolID>{}) { 87 Symbol* sym = SymbolTable::new_permanent_symbol(string); 88 Symbol::_vm_symbols[as_int(index)] = sym; 89 string += strlen(string); // skip string body 90 string += 1; // skip trailing null 91 } 92 93 _type_signatures[T_BYTE] = byte_signature(); 94 _type_signatures[T_CHAR] = char_signature(); 95 _type_signatures[T_DOUBLE] = double_signature(); 96 _type_signatures[T_FLOAT] = float_signature(); 97 _type_signatures[T_INT] = int_signature(); 98 _type_signatures[T_LONG] = long_signature(); 99 _type_signatures[T_SHORT] = short_signature(); 100 _type_signatures[T_BOOLEAN] = bool_signature(); 101 _type_signatures[T_VOID] = void_signature(); 102 #ifdef ASSERT 103 for (int i = (int)T_BOOLEAN; i < (int)T_VOID+1; i++) { 104 Symbol* s = _type_signatures[i]; 105 if (s == nullptr) continue; 106 SignatureStream ss(s, false); 107 assert(ss.type() == i, "matching signature"); 108 assert(!ss.is_reference(), "no single-char signature for T_OBJECT, etc."); 109 } 110 #endif 111 } 112 113 #ifdef ASSERT 114 // Check for duplicates: 115 116 for (auto i1 : EnumRange<vmSymbolID>{}) { 117 Symbol* sym = symbol_at(i1); 118 for (auto i2 : EnumRange<vmSymbolID>{vmSymbolID::FIRST_SID, i1}) { 119 if (i2 != i1 && symbol_at(i2) == sym) { 120 tty->print("*** Duplicate VM symbol SIDs %s(%d) and %s(%d): \"", 121 vm_symbol_enum_name(i2), as_int(i2), 122 vm_symbol_enum_name(i1), as_int(i1)); 123 sym->print_symbol_on(tty); 124 tty->print_cr("\""); 125 } 126 } 127 } 128 #endif //ASSERT 129 130 // Create an index for find_id: 131 { 132 for (auto index : EnumRange<vmSymbolID>{}) { 133 vm_symbol_index[as_int(index)] = index; 134 } 135 int num_sids = SID_LIMIT-FIRST_SID; 136 qsort(&vm_symbol_index[FIRST_SID], num_sids, sizeof(vm_symbol_index[0]), 137 compare_vmsymbol_sid); 138 } 139 140 #ifdef ASSERT 141 { 142 // Spot-check correspondence between strings, symbols, and enums: 143 assert(Symbol::_vm_symbols[NO_SID] == nullptr, "must be"); 144 const char* str = "java/lang/Object"; 145 TempNewSymbol jlo = SymbolTable::new_permanent_symbol(str); 146 assert(strncmp(str, (char*)jlo->base(), jlo->utf8_length()) == 0, ""); 147 assert(jlo == java_lang_Object(), ""); 148 vmSymbolID sid = VM_SYMBOL_ENUM_NAME(java_lang_Object); 149 assert(find_sid(jlo) == sid, ""); 150 assert(symbol_at(sid) == jlo, ""); 151 152 // Make sure find_sid produces the right answer in each case. 153 for (auto index : EnumRange<vmSymbolID>{}) { 154 Symbol* sym = symbol_at(index); 155 sid = find_sid(sym); 156 assert(sid == index, "symbol index works"); 157 // Note: If there are duplicates, this assert will fail. 158 // A "Duplicate VM symbol" message will have already been printed. 159 } 160 161 // The string "format" happens (at the moment) not to be a vmSymbol, 162 // though it is a method name in java.lang.String. 163 str = "format"; 164 TempNewSymbol fmt = SymbolTable::new_permanent_symbol(str); 165 sid = find_sid(fmt); 166 assert(sid == vmSymbolID::NO_SID, "symbol index works (negative test)"); 167 } 168 #endif 169 } 170 171 172 #ifndef PRODUCT 173 const char* vmSymbols::name_for(vmSymbolID sid) { 174 if (sid == vmSymbolID::NO_SID) 175 return "NO_SID"; 176 const char* string = &vm_symbol_bodies[0]; 177 for (auto index : EnumRange<vmSymbolID>{}) { 178 if (index == sid) 179 return string; 180 string += strlen(string); // skip string body 181 string += 1; // skip trailing null 182 } 183 return "BAD_SID"; 184 } 185 #endif 186 187 188 189 void vmSymbols::symbols_do(SymbolClosure* f) { 190 for (auto index : EnumRange<vmSymbolID>{}) { 191 f->do_symbol(&Symbol::_vm_symbols[as_int(index)]); 192 } 193 for (int i = 0; i < T_VOID+1; i++) { 194 f->do_symbol(&_type_signatures[i]); 195 } 196 } 197 198 void vmSymbols::metaspace_pointers_do(MetaspaceClosure *closure) { 199 for (auto index : EnumRange<vmSymbolID>{}) { 200 closure->push(&Symbol::_vm_symbols[as_int(index)]); 201 } 202 for (int i = 0; i < T_VOID+1; i++) { 203 closure->push(&_type_signatures[i]); 204 } 205 } 206 207 void vmSymbols::serialize(SerializeClosure* soc) { 208 soc->do_ptrs((void**)&Symbol::_vm_symbols[FIRST_SID], 209 (SID_LIMIT - FIRST_SID) * sizeof(Symbol::_vm_symbols[0])); 210 soc->do_ptrs((void**)_type_signatures, sizeof(_type_signatures)); 211 } 212 213 #ifndef PRODUCT 214 static uint find_sid_calls, find_sid_probes; 215 // (Typical counts are calls=7000 and probes=17000.) 216 #endif 217 218 vmSymbolID vmSymbols::find_sid(const Symbol* symbol) { 219 static int mid_hint = FIRST_SID+1; 220 // Handle the majority of misses by a bounds check. 221 // Then, use a binary search over the index. 222 // Expected trip count is less than log2_SID_LIMIT, about eight. 223 // This is slow but acceptable, given that calls are not 224 // dynamically common. (Method*::intrinsic_id has a cache.) 225 NOT_PRODUCT(find_sid_calls++); 226 int min = FIRST_SID, max = SID_LIMIT - 1; 227 vmSymbolID sid = vmSymbolID::NO_SID, sid1; 228 int cmp1; 229 sid1 = vm_symbol_index[min]; 230 cmp1 = compare_symbol(symbol, Symbol::vm_symbol_at(sid1)); 231 if (cmp1 <= 0) { // before the first 232 if (cmp1 == 0) sid = sid1; 233 } else { 234 sid1 = vm_symbol_index[max]; 235 cmp1 = compare_symbol(symbol, symbol_at(sid1)); 236 if (cmp1 >= 0) { // after the last 237 if (cmp1 == 0) sid = sid1; 238 } else { 239 // After checking the extremes, do a binary search. 240 ++min; --max; // endpoints are done 241 int mid = mid_hint; // start at previous success 242 while (max >= min) { 243 assert(mid >= min && mid <= max, ""); 244 NOT_PRODUCT(find_sid_probes++); 245 sid1 = vm_symbol_index[mid]; 246 cmp1 = compare_symbol(symbol, symbol_at(sid1)); 247 if (cmp1 == 0) { 248 mid_hint = mid; 249 sid = sid1; 250 break; 251 } 252 if (cmp1 < 0) 253 max = mid - 1; // symbol < symbol_at(sid) 254 else 255 min = mid + 1; 256 257 // Pick a new probe point: 258 mid = (max + min) / 2; 259 } 260 } 261 } 262 263 #ifdef ASSERT 264 if (sid == vmSymbolID::NO_SID) { 265 return sid; 266 } 267 268 // Perform the exhaustive self-check the first 1000 calls, 269 // and every 100 calls thereafter. 270 static int find_sid_check_count = -2000; 271 if ((uint)++find_sid_check_count > (uint)100) { 272 if (find_sid_check_count > 0) find_sid_check_count = 0; 273 274 // Make sure this is the right answer, using linear search. 275 // (We have already proven that there are no duplicates in the list.) 276 vmSymbolID sid2 = vmSymbolID::NO_SID; 277 for (auto index : EnumRange<vmSymbolID>{}) { 278 Symbol* sym2 = symbol_at(index); 279 if (sym2 == symbol) { 280 sid2 = index; 281 break; 282 } 283 } 284 // Unless it's a duplicate, assert that the sids are the same. 285 if (Symbol::_vm_symbols[as_int(sid)] != Symbol::_vm_symbols[as_int(sid2)]) { 286 assert(sid == sid2, "binary same as linear search"); 287 } 288 } 289 #endif //ASSERT 290 291 return sid; 292 } 293 294 vmSymbolID vmSymbols::find_sid(const char* symbol_name) { 295 Symbol* symbol = SymbolTable::probe(symbol_name, (int) strlen(symbol_name)); 296 if (symbol == nullptr) return vmSymbolID::NO_SID; 297 return find_sid(symbol); 298 }