1 /* 2 * Copyright (c) 2023, 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 "memory/resourceArea.hpp" 26 #include "cds/cdsConfig.hpp" 27 #include "oops/fieldInfo.inline.hpp" 28 #include "runtime/atomic.hpp" 29 #include "utilities/packedTable.hpp" 30 31 void FieldInfo::print(outputStream* os, ConstantPool* cp) { 32 os->print_cr("index=%d name_index=%d name=%s signature_index=%d signature=%s offset=%d " 33 "AccessFlags=%d FieldFlags=%d " 34 "initval_index=%d gen_signature_index=%d, gen_signature=%s contended_group=%d", 35 index(), 36 name_index(), name(cp)->as_utf8(), 37 signature_index(), signature(cp)->as_utf8(), 38 offset(), 39 access_flags().as_field_flags(), 40 field_flags().as_uint(), 41 initializer_index(), 42 generic_signature_index(), 43 _field_flags.is_generic() ? (_field_flags.is_injected() ? 44 lookup_symbol(generic_signature_index())->as_utf8() : cp->symbol_at(generic_signature_index())->as_utf8() 45 ) : "", 46 is_contended() ? contended_group() : 0); 47 } 48 49 void FieldInfo::print_from_growable_array(outputStream* os, GrowableArray<FieldInfo>* array, ConstantPool* cp) { 50 for (int i = 0; i < array->length(); i++) { 51 array->adr_at(i)->print(os, cp); 52 } 53 } 54 55 Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fields, int java_fields, int injected_fields, 56 ClassLoaderData* loader_data, TRAPS) { 57 // The stream format described in fieldInfo.hpp is: 58 // FieldInfoStream := j=num_java_fields k=num_injected_fields Field[j+k] End 59 // Field := name sig offset access flags Optionals(flags) 60 // Optionals(i) := initval?[i&is_init] // ConstantValue attr 61 // gsig?[i&is_generic] // signature attr 62 // group?[i&is_contended] // Contended anno (group) 63 // End = 0 64 65 using StreamSizer = UNSIGNED5::Sizer<>; 66 using StreamFieldSizer = Mapper<StreamSizer>; 67 StreamSizer s; 68 StreamFieldSizer sizer(&s); 69 70 assert(fields->length() == java_fields + injected_fields, "must be"); 71 72 sizer.consumer()->accept_uint(java_fields); 73 sizer.consumer()->accept_uint(injected_fields); 74 for (int i = 0; i < fields->length(); i++) { 75 FieldInfo* fi = fields->adr_at(i); 76 sizer.map_field_info(*fi); 77 } 78 // Originally there was an extra byte with 0 terminating the reading; 79 // now we check limits instead. 80 int storage_size = sizer.consumer()->position(); 81 Array<u1>* const fis = MetadataFactory::new_array<u1>(loader_data, storage_size, CHECK_NULL); 82 83 using StreamWriter = UNSIGNED5::Writer<Array<u1>*, int, ArrayHelper<Array<u1>*, int>>; 84 using StreamFieldWriter = Mapper<StreamWriter>; 85 StreamWriter w(fis); 86 StreamFieldWriter writer(&w); 87 88 writer.consumer()->accept_uint(java_fields); 89 writer.consumer()->accept_uint(injected_fields); 90 for (int i = 0; i < fields->length(); i++) { 91 writer.map_field_info(fields->at(i)); 92 } 93 94 #ifdef ASSERT 95 FieldInfoReader r(fis); 96 int jfc, ifc; 97 r.read_field_counts(&jfc, &ifc); 98 assert(jfc == java_fields, "Must be"); 99 assert(ifc == injected_fields, "Must be"); 100 for (int i = 0; i < jfc + ifc; i++) { 101 FieldInfo fi; 102 r.read_field_info(fi); 103 FieldInfo* fi_ref = fields->adr_at(i); 104 assert(fi_ref->name_index() == fi.name_index(), "Must be"); 105 assert(fi_ref->signature_index() == fi.signature_index(), "Must be"); 106 assert(fi_ref->offset() == fi.offset(), "Must be"); 107 assert(fi_ref->access_flags().as_field_flags() == fi.access_flags().as_field_flags(), "Must be"); 108 assert(fi_ref->field_flags().as_uint() == fi.field_flags().as_uint(), " Must be"); 109 if(fi_ref->field_flags().is_initialized()) { 110 assert(fi_ref->initializer_index() == fi.initializer_index(), "Must be"); 111 } 112 if (fi_ref->field_flags().is_generic()) { 113 assert(fi_ref->generic_signature_index() == fi.generic_signature_index(), "Must be"); 114 } 115 if (fi_ref->field_flags().is_contended()) { 116 assert(fi_ref->contended_group() == fi.contended_group(), "Must be"); 117 } 118 if (fi_ref->field_flags().is_flat()) { 119 assert(fi_ref->layout_kind() == fi.layout_kind(), "Must be"); 120 } 121 if (fi_ref->field_flags().has_null_marker()) { 122 assert(fi_ref->null_marker_offset() == fi.null_marker_offset(), "Must be"); 123 } 124 } 125 #endif // ASSERT 126 127 return fis; 128 } 129 130 int FieldInfoStream::compare_name_and_sig(const Symbol* n1, const Symbol* s1, const Symbol* n2, const Symbol* s2) { 131 int cmp = n1->fast_compare(n2); 132 return cmp != 0 ? cmp : s1->fast_compare(s2); 133 } 134 135 136 // We use both name and signature during the comparison; while JLS require unique 137 // names for fields, JVMS requires only unique name + signature combination. 138 struct field_pos { 139 Symbol* _name; 140 Symbol* _signature; 141 int _index; 142 int _position; 143 }; 144 145 class FieldInfoSupplier: public PackedTableBuilder::Supplier { 146 const field_pos* _positions; 147 size_t _elements; 148 149 public: 150 FieldInfoSupplier(const field_pos* positions, size_t elements): _positions(positions), _elements(elements) {} 151 152 bool next(uint32_t* key, uint32_t* value) override { 153 if (_elements == 0) { 154 return false; 155 } 156 *key = _positions->_position; 157 *value = _positions->_index; 158 ++_positions; 159 --_elements; 160 return true; 161 } 162 }; 163 164 Array<u1>* FieldInfoStream::create_search_table(ConstantPool* cp, const Array<u1>* fis, ClassLoaderData* loader_data, TRAPS) { 165 if (CDSConfig::is_dumping_dynamic_archive()) { 166 // We cannot use search table; in case of dynamic archives it should be sorted by "requested" addresses, 167 // but Symbol* addresses are coming from _constants, which has "buffered" addresses. 168 // For background, see new comments inside allocate_node_impl in symbolTable.cpp 169 return nullptr; 170 } 171 172 FieldInfoReader r(fis); 173 int java_fields; 174 int injected_fields; 175 r.read_field_counts(&java_fields, &injected_fields); 176 assert(java_fields >= 0, "must be"); 177 if (java_fields == 0 || fis->length() == 0 || static_cast<uint>(java_fields) < BinarySearchThreshold) { 178 return nullptr; 179 } 180 181 ResourceMark rm; 182 field_pos* positions = NEW_RESOURCE_ARRAY(field_pos, java_fields); 183 for (int i = 0; i < java_fields; ++i) { 184 assert(r.has_next(), "number of fields must match"); 185 186 positions[i]._position = r.position(); 187 FieldInfo fi; 188 r.read_field_info(fi); 189 190 positions[i]._name = fi.name(cp); 191 positions[i]._signature = fi.signature(cp); 192 positions[i]._index = i; 193 } 194 auto compare_pair = [](const void* v1, const void* v2) { 195 const field_pos* p1 = reinterpret_cast<const field_pos*>(v1); 196 const field_pos* p2 = reinterpret_cast<const field_pos*>(v2); 197 return compare_name_and_sig(p1->_name, p1->_signature, p2->_name, p2->_signature); 198 }; 199 qsort(positions, java_fields, sizeof(field_pos), compare_pair); 200 201 PackedTableBuilder builder(fis->length() - 1, java_fields - 1); 202 Array<u1>* table = MetadataFactory::new_array<u1>(loader_data, java_fields * builder.element_bytes(), CHECK_NULL); 203 FieldInfoSupplier supplier(positions, java_fields); 204 builder.fill(table->data(), static_cast<size_t>(table->length()), supplier); 205 return table; 206 } 207 208 GrowableArray<FieldInfo>* FieldInfoStream::create_FieldInfoArray(const Array<u1>* fis, int* java_fields_count, int* injected_fields_count) { 209 FieldInfoReader r(fis); 210 r.read_field_counts(java_fields_count, injected_fields_count); 211 int length = *java_fields_count + *injected_fields_count; 212 213 GrowableArray<FieldInfo>* array = new GrowableArray<FieldInfo>(length); 214 while (r.has_next()) { 215 FieldInfo fi; 216 r.read_field_info(fi); 217 array->append(fi); 218 } 219 assert(array->length() == length, "Must be"); 220 return array; 221 } 222 223 void FieldInfoStream::print_from_fieldinfo_stream(Array<u1>* fis, outputStream* os, ConstantPool* cp) { 224 FieldInfoReader r(fis); 225 int java_fields_count; 226 int injected_fields_count; 227 r.read_field_counts(&java_fields_count, &injected_fields_count); 228 while (r.has_next()) { 229 FieldInfo fi; 230 r.read_field_info(fi); 231 fi.print(os, cp); 232 } 233 } 234 235 class FieldInfoComparator: public PackedTableLookup::Comparator { 236 const FieldInfoReader* _reader; 237 ConstantPool* _cp; 238 const Symbol* _name; 239 const Symbol* _signature; 240 241 public: 242 FieldInfoComparator(const FieldInfoReader* reader, ConstantPool* cp, const Symbol* name, const Symbol* signature): 243 _reader(reader), _cp(cp), _name(name), _signature(signature) {} 244 245 int compare_to(uint32_t position) override { 246 FieldInfoReader r2(*_reader); 247 r2.set_position_and_next_index(position, -1); 248 u2 name_index, sig_index; 249 r2.read_name_and_signature(&name_index, &sig_index); 250 Symbol* mid_name = _cp->symbol_at(name_index); 251 Symbol* mid_sig = _cp->symbol_at(sig_index); 252 253 return FieldInfoStream::compare_name_and_sig(_name, _signature, mid_name, mid_sig); 254 } 255 256 #ifdef ASSERT 257 void reset(uint32_t position) override { 258 FieldInfoReader r2(*_reader); 259 r2.set_position_and_next_index(position, -1); 260 u2 name_index, signature_index; 261 r2.read_name_and_signature(&name_index, &signature_index); 262 _name = _cp->symbol_at(name_index); 263 _signature = _cp->symbol_at(signature_index); 264 } 265 #endif // ASSERT 266 }; 267 268 #ifdef ASSERT 269 void FieldInfoStream::validate_search_table(ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table) { 270 if (search_table == nullptr) { 271 return; 272 } 273 FieldInfoReader reader(fis); 274 int java_fields, injected_fields; 275 reader.read_field_counts(&java_fields, &injected_fields); 276 assert(java_fields > 0, "must be"); 277 278 PackedTableLookup lookup(fis->length() - 1, java_fields - 1, search_table); 279 assert(lookup.element_bytes() * java_fields == static_cast<unsigned int>(search_table->length()), "size does not match"); 280 281 FieldInfoComparator comparator(&reader, cp, nullptr, nullptr); 282 // Check 1: assert that elements have the correct order based on the comparison function 283 lookup.validate_order(comparator); 284 285 // Check 2: Iterate through the original stream (not just search_table) and try if lookup works as expected 286 reader.set_position_and_next_index(0, 0); 287 reader.read_field_counts(&java_fields, &injected_fields); 288 while (reader.has_next()) { 289 int field_start = reader.position(); 290 FieldInfo fi; 291 reader.read_field_info(fi); 292 if (fi.field_flags().is_injected()) { 293 // checking only java fields that precede injected ones 294 break; 295 } 296 297 FieldInfoReader r2(fis); 298 int index = r2.search_table_lookup(search_table, fi.name(cp), fi.signature(cp), cp, java_fields); 299 assert(index == static_cast<int>(fi.index()), "wrong index: %d != %u", index, fi.index()); 300 assert(index == r2.next_index(), "index should match"); 301 assert(field_start == r2.position(), "must find the same position"); 302 } 303 } 304 #endif // ASSERT 305 306 void FieldInfoStream::print_search_table(outputStream* st, ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table) { 307 if (search_table == nullptr) { 308 return; 309 } 310 FieldInfoReader reader(fis); 311 int java_fields, injected_fields; 312 reader.read_field_counts(&java_fields, &injected_fields); 313 assert(java_fields > 0, "must be"); 314 PackedTableLookup lookup(fis->length() - 1, java_fields - 1, search_table); 315 auto printer = [&] (size_t offset, uint32_t position, uint32_t index) { 316 reader.set_position_and_next_index(position, -1); 317 u2 name_index, sig_index; 318 reader.read_name_and_signature(&name_index, &sig_index); 319 Symbol* name = cp->symbol_at(name_index); 320 Symbol* sig = cp->symbol_at(sig_index); 321 st->print(" [%zu] #%d,#%d = ", offset, name_index, sig_index); 322 name->print_symbol_on(st); 323 st->print(":"); 324 sig->print_symbol_on(st); 325 st->print(" @ %p,%p", name, sig); 326 st->cr(); 327 }; 328 329 lookup.iterate(printer); 330 } 331 332 int FieldInfoReader::search_table_lookup(const Array<u1>* search_table, const Symbol* name, const Symbol* signature, ConstantPool* cp, int java_fields) { 333 assert(java_fields >= 0, "must be"); 334 if (java_fields == 0) { 335 return -1; 336 } 337 FieldInfoComparator comp(this, cp, name, signature); 338 PackedTableLookup lookup(_r.limit() - 1, java_fields - 1, search_table); 339 uint32_t position; 340 static_assert(sizeof(uint32_t) == sizeof(_next_index), "field size assert"); 341 if (lookup.search(comp, &position, reinterpret_cast<uint32_t*>(&_next_index))) { 342 _r.set_position(static_cast<int>(position)); 343 return _next_index; 344 } else { 345 return -1; 346 } 347 }