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 }