2222 *
2323 */
2424
25+ #include " memory/resourceArea.hpp"
26+ #include " cds/cdsConfig.hpp"
2527#include " oops/fieldInfo.inline.hpp"
2628#include " runtime/atomic.hpp"
29+ #include " utilities/packedTable.hpp"
2730
2831void FieldInfo::print (outputStream* os, ConstantPool* cp) {
2932 os->print_cr (" index=%d name_index=%d name=%s signature_index=%d signature=%s offset=%d "
@@ -37,8 +40,10 @@ void FieldInfo::print(outputStream* os, ConstantPool* cp) {
3740 field_flags ().as_uint (),
3841 initializer_index (),
3942 generic_signature_index (),
40- _field_flags.is_injected () ? lookup_symbol (generic_signature_index ())->as_utf8 () : cp->symbol_at (generic_signature_index ())->as_utf8 (),
41- contended_group ());
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 );
4247}
4348
4449void FieldInfo::print_from_growable_array (outputStream* os, GrowableArray<FieldInfo>* array, ConstantPool* cp) {
@@ -62,13 +67,17 @@ Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fie
6267 StreamSizer s;
6368 StreamFieldSizer sizer (&s);
6469
70+ assert (fields->length () == java_fields + injected_fields, " must be" );
71+
6572 sizer.consumer ()->accept_uint (java_fields);
6673 sizer.consumer ()->accept_uint (injected_fields);
6774 for (int i = 0 ; i < fields->length (); i++) {
6875 FieldInfo* fi = fields->adr_at (i);
6976 sizer.map_field_info (*fi);
7077 }
71- int storage_size = sizer.consumer ()->position () + 1 ;
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 ();
7281 Array<u1>* const fis = MetadataFactory::new_array<u1>(loader_data, storage_size, CHECK_NULL);
7382
7483 using StreamWriter = UNSIGNED5::Writer<Array<u1>*, int , ArrayHelper<Array<u1>*, int >>;
@@ -79,15 +88,14 @@ Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fie
7988 writer.consumer ()->accept_uint (java_fields);
8089 writer.consumer ()->accept_uint (injected_fields);
8190 for (int i = 0 ; i < fields->length (); i++) {
82- FieldInfo* fi = fields->adr_at (i);
83- writer.map_field_info (*fi);
91+ writer.map_field_info (fields->at (i));
8492 }
8593
8694#ifdef ASSERT
8795 FieldInfoReader r (fis);
88- int jfc = r.next_uint ();
96+ int jfc, ifc;
97+ r.read_field_counts (&jfc, &ifc);
8998 assert (jfc == java_fields, " Must be" );
90- int ifc = r.next_uint ();
9199 assert (ifc == injected_fields, " Must be" );
92100 for (int i = 0 ; i < jfc + ifc; i++) {
93101 FieldInfo fi;
@@ -113,30 +121,221 @@ Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fie
113121 return fis;
114122}
115123
124+ int FieldInfoStream::compare_name_and_sig (const Symbol* n1, const Symbol* s1, const Symbol* n2, const Symbol* s2) {
125+ int cmp = n1->fast_compare (n2);
126+ return cmp != 0 ? cmp : s1->fast_compare (s2);
127+ }
128+
129+
130+ // We use both name and signature during the comparison; while JLS require unique
131+ // names for fields, JVMS requires only unique name + signature combination.
132+ struct field_pos {
133+ Symbol* _name;
134+ Symbol* _signature;
135+ int _index;
136+ int _position;
137+ };
138+
139+ class FieldInfoSupplier : public PackedTableBuilder ::Supplier {
140+ const field_pos* _positions;
141+ size_t _elements;
142+
143+ public:
144+ FieldInfoSupplier (const field_pos* positions, size_t elements): _positions(positions), _elements(elements) {}
145+
146+ bool next (uint32_t * key, uint32_t * value) override {
147+ if (_elements == 0 ) {
148+ return false ;
149+ }
150+ *key = _positions->_position ;
151+ *value = _positions->_index ;
152+ ++_positions;
153+ --_elements;
154+ return true ;
155+ }
156+ };
157+
158+ Array<u1>* FieldInfoStream::create_search_table (ConstantPool* cp, const Array<u1>* fis, ClassLoaderData* loader_data, TRAPS) {
159+ if (CDSConfig::is_dumping_dynamic_archive ()) {
160+ // We cannot use search table; in case of dynamic archives it should be sorted by "requested" addresses,
161+ // but Symbol* addresses are coming from _constants, which has "buffered" addresses.
162+ // For background, see new comments inside allocate_node_impl in symbolTable.cpp
163+ return nullptr ;
164+ }
165+
166+ FieldInfoReader r (fis);
167+ int java_fields;
168+ int injected_fields;
169+ r.read_field_counts (&java_fields, &injected_fields);
170+ assert (java_fields >= 0 , " must be" );
171+ if (java_fields == 0 || fis->length () == 0 || static_cast <uint>(java_fields) < BinarySearchThreshold) {
172+ return nullptr ;
173+ }
174+
175+ ResourceMark rm;
176+ field_pos* positions = NEW_RESOURCE_ARRAY (field_pos, java_fields);
177+ for (int i = 0 ; i < java_fields; ++i) {
178+ assert (r.has_next (), " number of fields must match" );
179+
180+ positions[i]._position = r.position ();
181+ FieldInfo fi;
182+ r.read_field_info (fi);
183+
184+ positions[i]._name = fi.name (cp);
185+ positions[i]._signature = fi.signature (cp);
186+ positions[i]._index = i;
187+ }
188+ auto compare_pair = [](const void * v1, const void * v2) {
189+ const field_pos* p1 = reinterpret_cast <const field_pos*>(v1);
190+ const field_pos* p2 = reinterpret_cast <const field_pos*>(v2);
191+ return compare_name_and_sig (p1->_name , p1->_signature , p2->_name , p2->_signature );
192+ };
193+ qsort (positions, java_fields, sizeof (field_pos), compare_pair);
194+
195+ PackedTableBuilder builder (fis->length () - 1 , java_fields - 1 );
196+ Array<u1>* table = MetadataFactory::new_array<u1>(loader_data, java_fields * builder.element_bytes (), CHECK_NULL);
197+ FieldInfoSupplier supplier (positions, java_fields);
198+ builder.fill (table->data (), static_cast <size_t >(table->length ()), supplier);
199+ return table;
200+ }
201+
116202GrowableArray<FieldInfo>* FieldInfoStream::create_FieldInfoArray (const Array<u1>* fis, int * java_fields_count, int * injected_fields_count) {
117- int length = FieldInfoStream::num_total_fields (fis);
118- GrowableArray<FieldInfo>* array = new GrowableArray<FieldInfo>(length);
119203 FieldInfoReader r (fis);
120- *java_fields_count = r.next_uint ();
121- *injected_fields_count = r.next_uint ();
204+ r.read_field_counts (java_fields_count, injected_fields_count);
205+ int length = *java_fields_count + *injected_fields_count;
206+
207+ GrowableArray<FieldInfo>* array = new GrowableArray<FieldInfo>(length);
122208 while (r.has_next ()) {
123209 FieldInfo fi;
124210 r.read_field_info (fi);
125211 array->append (fi);
126212 }
127213 assert (array->length () == length, " Must be" );
128- assert (array->length () == *java_fields_count + *injected_fields_count, " Must be" );
129214 return array;
130215}
131216
132217void FieldInfoStream::print_from_fieldinfo_stream (Array<u1>* fis, outputStream* os, ConstantPool* cp) {
133- int length = FieldInfoStream::num_total_fields (fis);
134218 FieldInfoReader r (fis);
135- int java_field_count = r.next_uint ();
136- int injected_fields_count = r.next_uint ();
219+ int java_fields_count;
220+ int injected_fields_count;
221+ r.read_field_counts (&java_fields_count, &injected_fields_count);
137222 while (r.has_next ()) {
138223 FieldInfo fi;
139224 r.read_field_info (fi);
140225 fi.print (os, cp);
141226 }
142227}
228+
229+ class FieldInfoComparator : public PackedTableLookup ::Comparator {
230+ const FieldInfoReader* _reader;
231+ ConstantPool* _cp;
232+ const Symbol* _name;
233+ const Symbol* _signature;
234+
235+ public:
236+ FieldInfoComparator (const FieldInfoReader* reader, ConstantPool* cp, const Symbol* name, const Symbol* signature):
237+ _reader (reader), _cp(cp), _name(name), _signature(signature) {}
238+
239+ int compare_to (uint32_t position) override {
240+ FieldInfoReader r2 (*_reader);
241+ r2.set_position_and_next_index (position, -1 );
242+ u2 name_index, sig_index;
243+ r2.read_name_and_signature (&name_index, &sig_index);
244+ Symbol* mid_name = _cp->symbol_at (name_index);
245+ Symbol* mid_sig = _cp->symbol_at (sig_index);
246+
247+ return FieldInfoStream::compare_name_and_sig (_name, _signature, mid_name, mid_sig);
248+ }
249+
250+ #ifdef ASSERT
251+ void reset (uint32_t position) override {
252+ FieldInfoReader r2 (*_reader);
253+ r2.set_position_and_next_index (position, -1 );
254+ u2 name_index, signature_index;
255+ r2.read_name_and_signature (&name_index, &signature_index);
256+ _name = _cp->symbol_at (name_index);
257+ _signature = _cp->symbol_at (signature_index);
258+ }
259+ #endif // ASSERT
260+ };
261+
262+ #ifdef ASSERT
263+ void FieldInfoStream::validate_search_table (ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table) {
264+ if (search_table == nullptr ) {
265+ return ;
266+ }
267+ FieldInfoReader reader (fis);
268+ int java_fields, injected_fields;
269+ reader.read_field_counts (&java_fields, &injected_fields);
270+ assert (java_fields > 0 , " must be" );
271+
272+ PackedTableLookup lookup (fis->length () - 1 , java_fields - 1 , search_table);
273+ assert (lookup.element_bytes () * java_fields == static_cast <unsigned int >(search_table->length ()), " size does not match" );
274+
275+ FieldInfoComparator comparator (&reader, cp, nullptr , nullptr );
276+ // Check 1: assert that elements have the correct order based on the comparison function
277+ lookup.validate_order (comparator);
278+
279+ // Check 2: Iterate through the original stream (not just search_table) and try if lookup works as expected
280+ reader.set_position_and_next_index (0 , 0 );
281+ reader.read_field_counts (&java_fields, &injected_fields);
282+ while (reader.has_next ()) {
283+ int field_start = reader.position ();
284+ FieldInfo fi;
285+ reader.read_field_info (fi);
286+ if (fi.field_flags ().is_injected ()) {
287+ // checking only java fields that precede injected ones
288+ break ;
289+ }
290+
291+ FieldInfoReader r2 (fis);
292+ int index = r2.search_table_lookup (search_table, fi.name (cp), fi.signature (cp), cp, java_fields);
293+ assert (index == static_cast <int >(fi.index ()), " wrong index: %d != %u" , index, fi.index ());
294+ assert (index == r2.next_index (), " index should match" );
295+ assert (field_start == r2.position (), " must find the same position" );
296+ }
297+ }
298+ #endif // ASSERT
299+
300+ void FieldInfoStream::print_search_table (outputStream* st, ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table) {
301+ if (search_table == nullptr ) {
302+ return ;
303+ }
304+ FieldInfoReader reader (fis);
305+ int java_fields, injected_fields;
306+ reader.read_field_counts (&java_fields, &injected_fields);
307+ assert (java_fields > 0 , " must be" );
308+ PackedTableLookup lookup (fis->length () - 1 , java_fields - 1 , search_table);
309+ auto printer = [&] (size_t offset, uint32_t position, uint32_t index) {
310+ reader.set_position_and_next_index (position, -1 );
311+ u2 name_index, sig_index;
312+ reader.read_name_and_signature (&name_index, &sig_index);
313+ Symbol* name = cp->symbol_at (name_index);
314+ Symbol* sig = cp->symbol_at (sig_index);
315+ st->print (" [%zu] #%d,#%d = " , offset, name_index, sig_index);
316+ name->print_symbol_on (st);
317+ st->print (" :" );
318+ sig->print_symbol_on (st);
319+ st->print (" @ %p,%p" , name, sig);
320+ st->cr ();
321+ };
322+
323+ lookup.iterate(printer);
324+ }
325+
326+ int FieldInfoReader::search_table_lookup (const Array<u1>* search_table, const Symbol* name, const Symbol* signature, ConstantPool* cp, int java_fields) {
327+ assert (java_fields >= 0 , " must be" );
328+ if (java_fields == 0 ) {
329+ return -1 ;
330+ }
331+ FieldInfoComparator comp (this , cp, name, signature);
332+ PackedTableLookup lookup (_r.limit () - 1 , java_fields - 1 , search_table);
333+ uint32_t position;
334+ static_assert (sizeof (uint32_t ) == sizeof (_next_index), " field size assert" );
335+ if (lookup.search (comp, &position, reinterpret_cast <uint32_t *>(&_next_index))) {
336+ _r.set_position (static_cast <int >(position));
337+ return _next_index;
338+ } else {
339+ return -1 ;
340+ }
341+ }
0 commit comments