68 // Buckets without entry are skipped from the table. Their offsets are |
71 // Buckets without entry are skipped from the table. Their offsets are |
69 // still written out for faster lookup. |
72 // still written out for faster lookup. |
70 // |
73 // |
71 class CompactHashtableWriter: public StackObj { |
74 class CompactHashtableWriter: public StackObj { |
72 public: |
75 public: |
73 class Entry: public CHeapObj<mtSymbol> { |
76 class Entry VALUE_OBJ_CLASS_SPEC { |
74 Entry* _next; |
|
75 unsigned int _hash; |
77 unsigned int _hash; |
76 void* _literal; |
78 u4 _value; |
77 |
79 |
78 public: |
80 public: |
79 Entry(unsigned int hash, Symbol *symbol) : _next(NULL), _hash(hash), _literal(symbol) {} |
81 Entry() {} |
80 Entry(unsigned int hash, oop string) : _next(NULL), _hash(hash), _literal(string) {} |
82 Entry(unsigned int hash, u4 val) : _hash(hash), _value(val) {} |
81 |
83 |
82 void *value() { |
84 u4 value() { |
83 return _literal; |
85 return _value; |
84 } |
|
85 Symbol *symbol() { |
|
86 return (Symbol*)_literal; |
|
87 } |
|
88 oop string() { |
|
89 return (oop)_literal; |
|
90 } |
86 } |
91 unsigned int hash() { |
87 unsigned int hash() { |
92 return _hash; |
88 return _hash; |
93 } |
89 } |
94 Entry *next() {return _next;} |
90 |
95 void set_next(Entry *p) {_next = p;} |
91 bool operator==(const CompactHashtableWriter::Entry& other) { |
|
92 return (_value == other._value && _hash == other._hash); |
|
93 } |
96 }; // class CompactHashtableWriter::Entry |
94 }; // class CompactHashtableWriter::Entry |
97 |
95 |
98 private: |
96 private: |
99 static int number_of_buckets(int num_entries); |
|
100 |
|
101 int _type; |
|
102 int _num_entries; |
97 int _num_entries; |
103 int _num_buckets; |
98 int _num_buckets; |
104 juint* _bucket_sizes; |
99 int _num_empty_buckets; |
105 Entry** _buckets; |
100 int _num_value_only_buckets; |
106 int _required_bytes; |
101 int _num_other_buckets; |
|
102 GrowableArray<Entry>** _buckets; |
107 CompactHashtableStats* _stats; |
103 CompactHashtableStats* _stats; |
|
104 Array<u4>* _compact_buckets; |
|
105 Array<u4>* _compact_entries; |
108 |
106 |
109 public: |
107 public: |
110 // This is called at dump-time only |
108 // This is called at dump-time only |
111 CompactHashtableWriter(int table_type, int num_entries, CompactHashtableStats* stats); |
109 CompactHashtableWriter(int num_buckets, CompactHashtableStats* stats); |
112 ~CompactHashtableWriter(); |
110 ~CompactHashtableWriter(); |
113 |
111 |
114 int get_required_bytes() { |
112 void add(unsigned int hash, u4 value); |
115 return _required_bytes; |
113 void add(u4 value) { |
116 } |
114 add((unsigned int)value, value); |
117 |
115 } |
118 inline void add(unsigned int hash, Symbol* symbol); |
|
119 inline void add(unsigned int hash, oop string); |
|
120 |
116 |
121 private: |
117 private: |
122 void add(unsigned int hash, Entry* entry); |
118 void allocate_table(); |
123 juint* dump_table(juint* p, juint** first_bucket, NumberSeq* summary); |
119 void dump_table(NumberSeq* summary); |
124 juint* dump_buckets(juint* table, juint* p, NumberSeq* summary); |
120 |
125 |
121 public: |
126 public: |
122 void dump(SimpleCompactHashtable *cht, const char* table_name); |
127 void dump(char** top, char* end); |
|
128 const char* table_name(); |
123 const char* table_name(); |
129 }; |
124 }; |
130 |
125 |
|
126 class CompactSymbolTableWriter: public CompactHashtableWriter { |
|
127 public: |
|
128 CompactSymbolTableWriter(int num_buckets, CompactHashtableStats* stats) : |
|
129 CompactHashtableWriter(num_buckets, stats) {} |
|
130 void add(unsigned int hash, Symbol *symbol); |
|
131 void dump(CompactHashtable<Symbol*, char> *cht); |
|
132 }; |
|
133 |
|
134 class CompactStringTableWriter: public CompactHashtableWriter { |
|
135 public: |
|
136 CompactStringTableWriter(int num_entries, CompactHashtableStats* stats) : |
|
137 CompactHashtableWriter(num_entries, stats) {} |
|
138 void add(unsigned int hash, oop string); |
|
139 void dump(CompactHashtable<oop, char> *cht); |
|
140 }; |
|
141 |
131 #define REGULAR_BUCKET_TYPE 0 |
142 #define REGULAR_BUCKET_TYPE 0 |
132 #define COMPACT_BUCKET_TYPE 1 |
143 #define VALUE_ONLY_BUCKET_TYPE 1 |
133 #define TABLEEND_BUCKET_TYPE 3 |
144 #define TABLEEND_BUCKET_TYPE 3 |
134 #define BUCKET_OFFSET_MASK 0x3FFFFFFF |
145 #define BUCKET_OFFSET_MASK 0x3FFFFFFF |
135 #define BUCKET_OFFSET(info) ((info) & BUCKET_OFFSET_MASK) |
146 #define BUCKET_OFFSET(info) ((info) & BUCKET_OFFSET_MASK) |
136 #define BUCKET_TYPE_SHIFT 30 |
147 #define BUCKET_TYPE_SHIFT 30 |
137 #define BUCKET_TYPE(info) (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT) |
148 #define BUCKET_TYPE(info) (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT) |
144 // |
155 // |
145 // Because these tables are read-only (no entries can be added/deleted) at run-time |
156 // Because these tables are read-only (no entries can be added/deleted) at run-time |
146 // and tend to have large number of entries, we try to minimize the footprint |
157 // and tend to have large number of entries, we try to minimize the footprint |
147 // cost per entry. |
158 // cost per entry. |
148 // |
159 // |
149 // Layout of compact table in the shared archive: |
160 // The CompactHashtable is split into two arrays |
150 // |
161 // |
151 // uintx base_address; |
162 // u4 buckets[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset |
152 // juint num_entries; |
163 // u4 entries[<variable size>] |
153 // juint num_buckets; |
164 // |
154 // juint bucket_infos[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset |
165 // The size of buckets[] is 'num_buckets + 1'. Each entry of |
155 // juint table[] |
166 // buckets[] is a 32-bit encoding of the bucket type and bucket offset, |
156 // |
|
157 // ----------------------------------- |
|
158 // | base_address | num_entries | |
|
159 // |---------------------------------| |
|
160 // | num_buckets | bucket_info0 | |
|
161 // |---------------------------------| |
|
162 // | bucket_info1 | bucket_info2 | |
|
163 // | bucket_info3 ... | |
|
164 // | .... | table_end_info | |
|
165 // |---------------------------------| |
|
166 // | entry0 | |
|
167 // | entry1 | |
|
168 // | entry2 | |
|
169 // | | |
|
170 // | ... | |
|
171 // ----------------------------------- |
|
172 // |
|
173 // The size of the bucket_info table is 'num_buckets + 1'. Each entry of the |
|
174 // bucket_info table is a 32-bit encoding of the bucket type and bucket offset, |
|
175 // with the type in the left-most 2-bit and offset in the remaining 30-bit. |
167 // with the type in the left-most 2-bit and offset in the remaining 30-bit. |
176 // The last entry is a special type. It contains the offset of the last |
168 // The last entry is a special type. It contains the end of the last |
177 // bucket end. We use that information when traversing the compact table. |
169 // bucket. |
178 // |
170 // |
179 // There are two types of buckets, regular buckets and compact buckets. The |
171 // There are two types of buckets, regular buckets and value_only buckets. The |
180 // compact buckets have '01' in their highest 2-bit, and regular buckets have |
172 // value_only buckets have '01' in their highest 2-bit, and regular buckets have |
181 // '00' in their highest 2-bit. |
173 // '00' in their highest 2-bit. |
182 // |
174 // |
183 // For normal buckets, each entry is 8 bytes in the table[]: |
175 // For normal buckets, each entry is 8 bytes in the entries[]: |
184 // juint hash; /* symbol/string hash */ |
176 // u4 hash; /* symbol/string hash */ |
185 // union { |
177 // union { |
186 // juint offset; /* Symbol* sym = (Symbol*)(base_address + offset) */ |
178 // u4 offset; /* Symbol* sym = (Symbol*)(base_address + offset) */ |
187 // narrowOop str; /* String narrowOop encoding */ |
179 // narrowOop str; /* String narrowOop encoding */ |
188 // } |
180 // } |
189 // |
181 // |
190 // |
182 // |
191 // For compact buckets, each entry has only the 4-byte 'offset' in the table[]. |
183 // For value_only buckets, each entry has only the 4-byte 'offset' in the entries[]. |
|
184 // |
|
185 // Example -- note that the second bucket is a VALUE_ONLY_BUCKET_TYPE so the hash code |
|
186 // is skipped. |
|
187 // buckets[0, 4, 5, ....] |
|
188 // | | | |
|
189 // | | +---+ |
|
190 // | | | |
|
191 // | +----+ | |
|
192 // v v v |
|
193 // entries[H,O,H,O,O,H,O,H,O.....] |
192 // |
194 // |
193 // See CompactHashtable::lookup() for how the table is searched at runtime. |
195 // See CompactHashtable::lookup() for how the table is searched at runtime. |
194 // See CompactHashtableWriter::dump() for how the table is written at CDS |
196 // See CompactHashtableWriter::dump() for how the table is written at CDS |
195 // dump time. |
197 // dump time. |
196 // |
198 // |
197 template <class T, class N> class CompactHashtable VALUE_OBJ_CLASS_SPEC { |
199 class SimpleCompactHashtable VALUE_OBJ_CLASS_SPEC { |
|
200 protected: |
|
201 address _base_address; |
|
202 u4 _bucket_count; |
|
203 u4 _entry_count; |
|
204 u4* _buckets; |
|
205 u4* _entries; |
|
206 |
|
207 public: |
|
208 SimpleCompactHashtable() { |
|
209 _entry_count = 0; |
|
210 _bucket_count = 0; |
|
211 _buckets = 0; |
|
212 _entries = 0; |
|
213 } |
|
214 |
|
215 void reset() { |
|
216 _bucket_count = 0; |
|
217 _entry_count = 0; |
|
218 _buckets = 0; |
|
219 _entries = 0; |
|
220 } |
|
221 |
|
222 void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) { |
|
223 _base_address = base_address; |
|
224 _bucket_count = bucket_count; |
|
225 _entry_count = entry_count; |
|
226 _buckets = buckets; |
|
227 _entries = entries; |
|
228 } |
|
229 |
|
230 template <class I> inline void iterate(const I& iterator); |
|
231 |
|
232 bool exists(u4 value); |
|
233 |
|
234 // For reading from/writing to the CDS archive |
|
235 void serialize(SerializeClosure* soc); |
|
236 }; |
|
237 |
|
238 template <class T, class N> class CompactHashtable : public SimpleCompactHashtable { |
198 friend class VMStructs; |
239 friend class VMStructs; |
199 |
240 |
200 public: |
241 public: |
201 enum CompactHashtableType { |
242 enum CompactHashtableType { |
202 _symbol_table = 0, |
243 _symbol_table = 0, |
203 _string_table = 1 |
244 _string_table = 1 |
204 }; |
245 }; |
205 |
246 |
206 private: |
247 private: |
207 CompactHashtableType _type; |
248 u4 _type; |
208 uintx _base_address; |
249 |
209 juint _entry_count; |
250 inline Symbol* decode_entry(CompactHashtable<Symbol*, char>* const t, |
210 juint _bucket_count; |
251 u4 offset, const char* name, int len); |
211 juint _table_end_offset; |
252 |
212 juint* _buckets; |
253 inline oop decode_entry(CompactHashtable<oop, char>* const t, |
213 |
254 u4 offset, const char* name, int len); |
214 inline Symbol* lookup_entry(CompactHashtable<Symbol*, char>* const t, |
255 public: |
215 juint* addr, const char* name, int len); |
256 CompactHashtable() : SimpleCompactHashtable() {} |
216 |
257 |
217 inline oop lookup_entry(CompactHashtable<oop, char>* const t, |
258 void set_type(CompactHashtableType type) { |
218 juint* addr, const char* name, int len); |
259 _type = (u4)type; |
219 public: |
|
220 CompactHashtable() { |
|
221 _entry_count = 0; |
|
222 _bucket_count = 0; |
|
223 _table_end_offset = 0; |
|
224 _buckets = 0; |
|
225 } |
|
226 const char* init(CompactHashtableType type, const char *buffer); |
|
227 |
|
228 void reset() { |
|
229 _entry_count = 0; |
|
230 _bucket_count = 0; |
|
231 _table_end_offset = 0; |
|
232 _buckets = 0; |
|
233 } |
260 } |
234 |
261 |
235 // Lookup an entry from the compact table |
262 // Lookup an entry from the compact table |
236 inline T lookup(const N* name, unsigned int hash, int len); |
263 inline T lookup(const N* name, unsigned int hash, int len); |
237 |
264 |
238 // iterate over symbols |
265 // iterate over symbols |
239 void symbols_do(SymbolClosure *cl); |
266 void symbols_do(SymbolClosure *cl); |
240 |
267 |
241 // iterate over strings |
268 // iterate over strings |
242 void oops_do(OopClosure* f); |
269 void oops_do(OopClosure* f); |
|
270 |
|
271 // For reading from/writing to the CDS archive |
|
272 void serialize(SerializeClosure* soc); |
243 }; |
273 }; |
244 |
274 |
245 //////////////////////////////////////////////////////////////////////// |
275 //////////////////////////////////////////////////////////////////////// |
246 // |
276 // |
247 // Read/Write the contents of a hashtable textual dump (created by |
277 // Read/Write the contents of a hashtable textual dump (created by |