Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: runtime/vm/symbols.cc

Issue 397413002: Reimplement Symbols using hash table template. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/symbols.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/symbols.h" 5 #include "vm/symbols.h"
6 6
7 #include "vm/handles.h" 7 #include "vm/handles.h"
8 #include "vm/handles_impl.h" 8 #include "vm/handles_impl.h"
9 #include "vm/hash_table.h"
9 #include "vm/isolate.h" 10 #include "vm/isolate.h"
10 #include "vm/object.h" 11 #include "vm/object.h"
11 #include "vm/object_store.h" 12 #include "vm/object_store.h"
12 #include "vm/raw_object.h" 13 #include "vm/raw_object.h"
13 #include "vm/snapshot_ids.h" 14 #include "vm/snapshot_ids.h"
14 #include "vm/unicode.h" 15 #include "vm/unicode.h"
15 #include "vm/visitor.h" 16 #include "vm/visitor.h"
16 17
17 namespace dart { 18 namespace dart {
18 19
19 RawString* Symbols::predefined_[Symbols::kNumberOfOneCharCodeSymbols]; 20 RawString* Symbols::predefined_[Symbols::kNumberOfOneCharCodeSymbols];
20 String* Symbols::symbol_handles_[Symbols::kMaxPredefinedId]; 21 String* Symbols::symbol_handles_[Symbols::kMaxPredefinedId];
21 22
22 static const char* names[] = { 23 static const char* names[] = {
23 NULL, 24 NULL,
24 25
25 #define DEFINE_SYMBOL_LITERAL(symbol, literal) \ 26 #define DEFINE_SYMBOL_LITERAL(symbol, literal) \
26 literal, 27 literal,
27 PREDEFINED_SYMBOLS_LIST(DEFINE_SYMBOL_LITERAL) 28 PREDEFINED_SYMBOLS_LIST(DEFINE_SYMBOL_LITERAL)
28 #undef DEFINE_SYMBOL_LITERAL 29 #undef DEFINE_SYMBOL_LITERAL
29 30
30 "", // matches kKwTableStart. 31 "", // matches kKwTableStart.
31 32
32 #define DEFINE_KEYWORD_SYMBOL_INDEX(token, chars, ignore1, ignore2) \ 33 #define DEFINE_KEYWORD_SYMBOL_INDEX(token, chars, ignore1, ignore2) \
33 chars, 34 chars,
34 DART_KEYWORD_LIST(DEFINE_KEYWORD_SYMBOL_INDEX) 35 DART_KEYWORD_LIST(DEFINE_KEYWORD_SYMBOL_INDEX)
35 #undef DEFINE_KEYWORD_SYMBOL_INDEX 36 #undef DEFINE_KEYWORD_SYMBOL_INDEX
36 }; 37 };
37 38
38 intptr_t Symbols::num_of_grows_;
39 intptr_t Symbols::collision_count_[kMaxCollisionBuckets];
40
41 DEFINE_FLAG(bool, dump_symbol_stats, false, "Dump symbol table statistics"); 39 DEFINE_FLAG(bool, dump_symbol_stats, false, "Dump symbol table statistics");
42 40
43 41
44 const char* Symbols::Name(SymbolId symbol) { 42 const char* Symbols::Name(SymbolId symbol) {
45 ASSERT((symbol > kIllegal) && (symbol < kNullCharId)); 43 ASSERT((symbol > kIllegal) && (symbol < kNullCharId));
46 return names[symbol]; 44 return names[symbol];
47 } 45 }
48 46
49 47
50 const String& Symbols::Keyword(Token::Kind keyword) { 48 const String& Symbols::Keyword(Token::Kind keyword) {
51 const int kw_index = keyword - Token::kFirstKeyword; 49 const int kw_index = keyword - Token::kFirstKeyword;
52 ASSERT((0 <= kw_index) && (kw_index < Token::kNumKeywords)); 50 ASSERT((0 <= kw_index) && (kw_index < Token::kNumKeywords));
53 // First keyword symbol is in symbol_handles_[kKwTableStart + 1]. 51 // First keyword symbol is in symbol_handles_[kKwTableStart + 1].
54 const intptr_t keyword_id = Symbols::kKwTableStart + 1 + kw_index; 52 const intptr_t keyword_id = Symbols::kKwTableStart + 1 + kw_index;
55 ASSERT(symbol_handles_[keyword_id] != NULL); 53 ASSERT(symbol_handles_[keyword_id] != NULL);
56 return *symbol_handles_[keyword_id]; 54 return *symbol_handles_[keyword_id];
57 } 55 }
58 56
59 57
60 void Symbols::InitOnce(Isolate* isolate) { 58 void Symbols::InitOnce(Isolate* isolate) {
61 // Should only be run by the vm isolate. 59 // Should only be run by the vm isolate.
62 ASSERT(isolate == Dart::vm_isolate()); 60 ASSERT(isolate == Dart::vm_isolate());
63 61
64 if (FLAG_dump_symbol_stats) {
65 num_of_grows_ = 0;
66 for (intptr_t i = 0; i < kMaxCollisionBuckets; i++) {
67 collision_count_[i] = 0;
68 }
69 }
70
71 // Create and setup a symbol table in the vm isolate. 62 // Create and setup a symbol table in the vm isolate.
72 SetupSymbolTable(isolate); 63 SetupSymbolTable(isolate);
73 64
74 // Create all predefined symbols. 65 // Create all predefined symbols.
75 ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kNullCharId); 66 ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kNullCharId);
76 ObjectStore* object_store = isolate->object_store();
77 Array& symbol_table = Array::Handle();
78
79 67
80 // First set up all the predefined string symbols. 68 // First set up all the predefined string symbols.
81 for (intptr_t i = 1; i < Symbols::kKwTableStart; i++) { 69 for (intptr_t i = 1; i < Symbols::kKwTableStart; i++) {
82 // The symbol_table needs to be reloaded as it might have grown in the
83 // previous iteration.
84 symbol_table = object_store->symbol_table();
85 String* str = String::ReadOnlyHandle(); 70 String* str = String::ReadOnlyHandle();
86 *str = OneByteString::New(names[i], Heap::kOld); 71 *str = OneByteString::New(names[i], Heap::kOld);
87 Add(symbol_table, *str); 72 AddToVMIsolate(*str);
88 symbol_handles_[i] = str; 73 symbol_handles_[i] = str;
89 } 74 }
90 Object::RegisterSingletonClassNames(); 75 Object::RegisterSingletonClassNames();
91 76
92 // Create symbols for language keywords. Some keywords are equal to 77 // Create symbols for language keywords. Some keywords are equal to
93 // symbols we already created, so use New() instead of Add() to ensure 78 // symbols we already created, so use New() instead of Add() to ensure
94 // that the symbols are canonicalized. 79 // that the symbols are canonicalized.
95 for (intptr_t i = Symbols::kKwTableStart; i < Symbols::kNullCharId; i++) { 80 for (intptr_t i = Symbols::kKwTableStart; i < Symbols::kNullCharId; i++) {
96 String* str = String::ReadOnlyHandle(); 81 String* str = String::ReadOnlyHandle();
97 *str = New(names[i]); 82 *str = New(names[i]);
98 symbol_handles_[i] = str; 83 symbol_handles_[i] = str;
99 } 84 }
100 85
101 // Add Latin1 characters as Symbols, so that Symbols::FromCharCode is fast. 86 // Add Latin1 characters as Symbols, so that Symbols::FromCharCode is fast.
102 for (intptr_t c = 0; c < kNumberOfOneCharCodeSymbols; c++) { 87 for (intptr_t c = 0; c < kNumberOfOneCharCodeSymbols; c++) {
103 // The symbol_table needs to be reloaded as it might have grown in the
104 // previous iteration.
105 symbol_table = object_store->symbol_table();
106 intptr_t idx = (kNullCharId + c); 88 intptr_t idx = (kNullCharId + c);
107 ASSERT(idx < kMaxPredefinedId); 89 ASSERT(idx < kMaxPredefinedId);
108 ASSERT(Utf::IsLatin1(c)); 90 ASSERT(Utf::IsLatin1(c));
109 uint8_t ch = static_cast<uint8_t>(c); 91 uint8_t ch = static_cast<uint8_t>(c);
110 String* str = String::ReadOnlyHandle(); 92 String* str = String::ReadOnlyHandle();
111 *str = OneByteString::New(&ch, 1, Heap::kOld); 93 *str = OneByteString::New(&ch, 1, Heap::kOld);
112 Add(symbol_table, *str); 94 AddToVMIsolate(*str);
113 predefined_[c] = str->raw(); 95 predefined_[c] = str->raw();
114 symbol_handles_[idx] = str; 96 symbol_handles_[idx] = str;
115 } 97 }
116 } 98 }
117 99
118 100
101 RawString* StringFrom(const uint8_t* data, intptr_t len, Heap::Space space) {
102 return String::FromLatin1(data, len, space);
103 }
104 RawString* StringFrom(const uint16_t* data, intptr_t len, Heap::Space space) {
105 return String::FromUTF16(data, len, space);
106 }
107 RawString* StringFrom(const int32_t* data, intptr_t len, Heap::Space space) {
108 return String::FromUTF32(data, len, space);
109 }
110
111
112 template<typename CharType>
113 class CharArray {
114 public:
115 CharArray(const CharType* data, intptr_t len)
116 : data_(data), len_(len) {
117 hash_ = String::Hash(data, len);
118 }
119 RawString* ToSymbol() const {
120 String& result = String::Handle(StringFrom(data_, len_, Heap::kOld));
121 result.SetCanonical();
122 result.SetHash(hash_);
123 return result.raw();
124 }
125 bool Equals(const String& other) const {
126 return other.Equals(data_, len_);
127 }
128 intptr_t Hash() const { return hash_; }
129 private:
130 const CharType* data_;
131 intptr_t len_;
132 intptr_t hash_;
133 };
134 typedef CharArray<uint8_t> Latin1Array;
135 typedef CharArray<uint16_t> UTF16Array;
136 typedef CharArray<int32_t> UTF32Array;
137
138
139 class StringSlice {
140 public:
141 StringSlice(const String* str, intptr_t begin_index, intptr_t length)
Ivan Posva 2014/07/29 21:55:10 Why do you use "const String* str" instead of a re
koda 2014/07/29 22:31:50 A remnant from when this was just a struct. Change
142 : str_(str), begin_index_(begin_index), len_(length) {
143 hash_ = is_all() ? str->Hash() : String::Hash(*str, begin_index, length);
144 }
145 RawString* ToSymbol() const;
146 bool Equals(const String& other) const {
147 return other.Equals(*str_, begin_index_, len_);
148 }
149 intptr_t Hash() const { return hash_; }
150 private:
151 bool is_all() const { return begin_index_ == 0 && len_ == str_->Length(); }
152 const String* str_;
153 intptr_t begin_index_;
154 intptr_t len_;
155 intptr_t hash_;
156 };
157
158
159 RawString* StringSlice::ToSymbol() const {
160 if (is_all() && str_->IsOld()) {
161 str_->SetCanonical();
162 return str_->raw();
163 } else {
164 String& result = String::Handle(
165 String::SubString(*str_, begin_index_, len_, Heap::kOld));
166 result.SetCanonical();
167 result.SetHash(hash_);
168 return result.raw();
169 }
170 }
171
172
173 class SymbolTraits {
174 public:
175 static bool IsMatch(const Object& a, const Object& b) {
176 return String::Cast(a).Equals(String::Cast(b));
177 }
178 template<typename CharType>
Ivan Posva 2014/07/23 12:09:26 As below I would like to discuss this in person as
koda 2014/07/29 22:31:50 Acknowledged.
179 static bool IsMatch(const CharArray<CharType>& array, const Object& obj) {
180 return array.Equals(String::Cast(obj));
181 }
182 static bool IsMatch(const StringSlice& slice, const Object& obj) {
183 return slice.Equals(String::Cast(obj));
184 }
185 static uword Hash(const Object& key) {
186 return String::Cast(key).Hash();
187 }
188 template<typename CharType>
189 static uword Hash(const CharArray<CharType>& array) {
190 return array.Hash();
191 }
192 static uword Hash(const StringSlice& slice) {
193 return slice.Hash();
194 }
195 template<typename CharType>
196 static RawObject* NewKey(const CharArray<CharType>& array) {
197 return array.ToSymbol();
198 }
199 static RawObject* NewKey(const StringSlice& slice) {
200 return slice.ToSymbol();
201 }
202 };
203 typedef UnorderedHashSet<SymbolTraits> SymbolTable;
204
205
119 void Symbols::SetupSymbolTable(Isolate* isolate) { 206 void Symbols::SetupSymbolTable(Isolate* isolate) {
120 ASSERT(isolate != NULL); 207 ASSERT(isolate != NULL);
121 208
122 // Setup the symbol table used within the String class. 209 // Setup the symbol table used within the String class.
123 const intptr_t initial_size = (isolate == Dart::vm_isolate()) ? 210 const intptr_t initial_size = (isolate == Dart::vm_isolate()) ?
124 kInitialVMIsolateSymtabSize : kInitialSymtabSize; 211 kInitialVMIsolateSymtabSize : kInitialSymtabSize;
125 const Array& array = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); 212 Array& array =
126 213 Array::Handle(HashTables::New<SymbolTable>(initial_size, Heap::kOld));
127 // Last element contains the count of used slots.
128 array.SetAt(initial_size, Smi::Handle(Smi::New(0)));
129 isolate->object_store()->set_symbol_table(array); 214 isolate->object_store()->set_symbol_table(array);
130 } 215 }
131 216
132 217
133 intptr_t Symbols::Size(Isolate* isolate) { 218 void Symbols::GetStats(Isolate* isolate, intptr_t* size, intptr_t* capacity) {
134 ASSERT(isolate != NULL); 219 ASSERT(isolate != NULL);
135 Array& symbol_table = Array::Handle(isolate, 220 SymbolTable table(Array::Handle(isolate->object_store()->symbol_table()));
136 isolate->object_store()->symbol_table()); 221 *size = table.NumOccupied();
137 intptr_t table_size_index = symbol_table.Length() - 1; 222 *capacity = table.NumEntries();
138 dart::Smi& used = Smi::Handle(); 223 table.Release();
139 used ^= symbol_table.At(table_size_index);
140 return used.Value();
141 } 224 }
142 225
143 226
144 void Symbols::Add(const Array& symbol_table, const String& str) { 227 void Symbols::AddToVMIsolate(const String& str) {
145 // Should only be run by the vm isolate. 228 // Should only be run by the vm isolate.
146 ASSERT(Isolate::Current() == Dart::vm_isolate()); 229 ASSERT(Isolate::Current() == Dart::vm_isolate());
147 intptr_t hash = str.Hash(); 230 Isolate* isolate = Dart::vm_isolate();
148 intptr_t index = FindIndex(symbol_table, str, 0, str.Length(), hash); 231 Array& array = Array::Handle(isolate->object_store()->symbol_table());
149 ASSERT(symbol_table.At(index) == String::null()); 232 SymbolTable table(array);
150 InsertIntoSymbolTable(symbol_table, str, index); 233 bool present = table.Insert(str);
234 str.SetCanonical();
235 ASSERT(!present);
236 isolate->object_store()->set_symbol_table(array);
Ivan Posva 2014/07/23 12:09:26 I find this pattern really awkward. Reading just t
koda 2014/07/29 22:31:50 Acknowledged.
237 table.Release();
151 } 238 }
152 239
153 240
154 RawString* Symbols::New(const char* cstr, intptr_t len) { 241 RawString* Symbols::New(const char* cstr, intptr_t len) {
155 ASSERT((cstr != NULL) && (len >= 0)); 242 ASSERT((cstr != NULL) && (len >= 0));
156 const uint8_t* utf8_array = reinterpret_cast<const uint8_t*>(cstr); 243 const uint8_t* utf8_array = reinterpret_cast<const uint8_t*>(cstr);
157 return Symbols::FromUTF8(utf8_array, len); 244 return Symbols::FromUTF8(utf8_array, len);
158 } 245 }
159 246
160 247
(...skipping 11 matching lines...) Expand all
172 return FromLatin1(characters, len); 259 return FromLatin1(characters, len);
173 } 260 }
174 ASSERT((type == Utf8::kBMP) || (type == Utf8::kSupplementary)); 261 ASSERT((type == Utf8::kBMP) || (type == Utf8::kSupplementary));
175 uint16_t* characters = zone->Alloc<uint16_t>(len); 262 uint16_t* characters = zone->Alloc<uint16_t>(len);
176 Utf8::DecodeToUTF16(utf8_array, array_len, characters, len); 263 Utf8::DecodeToUTF16(utf8_array, array_len, characters, len);
177 return FromUTF16(characters, len); 264 return FromUTF16(characters, len);
178 } 265 }
179 266
180 267
181 RawString* Symbols::FromLatin1(const uint8_t* latin1_array, intptr_t len) { 268 RawString* Symbols::FromLatin1(const uint8_t* latin1_array, intptr_t len) {
182 return NewSymbol(latin1_array, len, String::FromLatin1); 269 return NewSymbol(Latin1Array(latin1_array, len));
183 } 270 }
184 271
185 272
186 RawString* Symbols::FromUTF16(const uint16_t* utf16_array, intptr_t len) { 273 RawString* Symbols::FromUTF16(const uint16_t* utf16_array, intptr_t len) {
187 return NewSymbol(utf16_array, len, String::FromUTF16); 274 return NewSymbol(UTF16Array(utf16_array, len));
188 } 275 }
189 276
190 277
191 RawString* Symbols::FromUTF32(const int32_t* utf32_array, intptr_t len) { 278 RawString* Symbols::FromUTF32(const int32_t* utf32_array, intptr_t len) {
192 return NewSymbol(utf32_array, len, String::FromUTF32); 279 return NewSymbol(UTF32Array(utf32_array, len));
193 } 280 }
194 281
195 282
196 template<typename CharacterType, typename CallbackType> 283 template<typename StringType>
Ivan Posva 2014/07/29 21:55:10 Please add a comment enumerating all possible Stri
koda 2014/07/29 22:31:49 Done.
197 RawString* Symbols::NewSymbol(const CharacterType* characters, 284 RawString* Symbols::NewSymbol(const StringType& str) {
198 intptr_t len, 285 String& symbol = String::Handle();
199 CallbackType new_string) { 286 {
200 Isolate* isolate = Isolate::Current(); 287 Isolate* isolate = Dart::vm_isolate();
201 String& symbol = String::Handle(isolate, String::null()); 288 Array& array = Array::Handle(isolate->object_store()->symbol_table());
202 Array& symbol_table = Array::Handle(isolate, Array::null()); 289 SymbolTable table(array);
203 290 symbol ^= table.GetOrNull(str);
204 // Calculate the String hash for this sequence of characters. 291 table.Release();
205 intptr_t hash = String::Hash(characters, len); 292 }
206
207 // First check if a symbol exists in the vm isolate for these characters.
208 symbol_table = Dart::vm_isolate()->object_store()->symbol_table();
209 intptr_t index = FindIndex(symbol_table, characters, len, hash);
210 symbol ^= symbol_table.At(index);
211 if (symbol.IsNull()) { 293 if (symbol.IsNull()) {
212 // Now try in the symbol table of the current isolate. 294 Isolate* isolate = Isolate::Current();
213 symbol_table = isolate->object_store()->symbol_table(); 295 Array& array = Array::Handle(isolate->object_store()->symbol_table());
214 index = FindIndex(symbol_table, characters, len, hash); 296 SymbolTable table(array);
215 // Since we leave enough room in the table to guarantee, that we find an 297 symbol ^= table.InsertNewOrGet(str);
216 // empty spot, index is the insertion point if symbol is null. 298 isolate->object_store()->set_symbol_table(array);
217 symbol ^= symbol_table.At(index); 299 table.Release();
218 if (symbol.IsNull()) {
219 // Allocate new result string.
220 symbol = (*new_string)(characters, len, Heap::kOld);
221 symbol.SetHash(hash); // Remember the calculated hash value.
222 InsertIntoSymbolTable(symbol_table, symbol, index);
223 }
224 } 300 }
225 ASSERT(symbol.IsSymbol()); 301 ASSERT(symbol.IsSymbol());
226 return symbol.raw(); 302 return symbol.raw();
227 } 303 }
228 304
229 305
230 template RawString* Symbols::NewSymbol(const uint8_t* characters,
231 intptr_t len,
232 RawString* (*new_string)(const uint8_t*,
233 intptr_t,
234 Heap::Space));
235 template RawString* Symbols::NewSymbol(const uint16_t* characters,
236 intptr_t len,
237 RawString* (*new_string)(const uint16_t*,
238 intptr_t,
239 Heap::Space));
240 template RawString* Symbols::NewSymbol(const int32_t* characters,
241 intptr_t len,
242 RawString* (*new_string)(const int32_t*,
243 intptr_t,
244 Heap::Space));
245
246
247 RawString* Symbols::New(const String& str) { 306 RawString* Symbols::New(const String& str) {
248 if (str.IsSymbol()) { 307 if (str.IsSymbol()) {
249 return str.raw(); 308 return str.raw();
250 } 309 }
251 return New(str, 0, str.Length()); 310 return New(str, 0, str.Length());
252 } 311 }
253 312
254 313
255 RawString* Symbols::New(const String& str, intptr_t begin_index, intptr_t len) { 314 RawString* Symbols::New(const String& str, intptr_t begin_index, intptr_t len) {
256 ASSERT(begin_index >= 0); 315 return NewSymbol(StringSlice(&str, begin_index, len));
257 ASSERT(len >= 0);
258 ASSERT((begin_index + len) <= str.Length());
259 Isolate* isolate = Isolate::Current();
260 ASSERT(isolate != Dart::vm_isolate());
261 String& symbol = String::Handle(isolate, String::null());
262 Array& symbol_table = Array::Handle(isolate, Array::null());
263
264 // Calculate the String hash for this sequence of characters.
265 intptr_t hash = (begin_index == 0 && len == str.Length()) ? str.Hash() :
266 String::Hash(str, begin_index, len);
267
268 // First check if a symbol exists in the vm isolate for these characters.
269 symbol_table = Dart::vm_isolate()->object_store()->symbol_table();
270 intptr_t index = FindIndex(symbol_table, str, begin_index, len, hash);
271 symbol ^= symbol_table.At(index);
272 if (symbol.IsNull()) {
273 // Now try in the symbol table of the current isolate.
274 symbol_table = isolate->object_store()->symbol_table();
275 index = FindIndex(symbol_table, str, begin_index, len, hash);
276 // Since we leave enough room in the table to guarantee, that we find an
277 // empty spot, index is the insertion point if symbol is null.
278 symbol ^= symbol_table.At(index);
279 if (symbol.IsNull()) {
280 if (str.IsOld() && begin_index == 0 && len == str.Length()) {
281 // Reuse the incoming str as the symbol value.
282 symbol = str.raw();
283 } else {
284 // Allocate a copy in old space.
285 symbol = String::SubString(str, begin_index, len, Heap::kOld);
286 symbol.SetHash(hash);
287 }
288 InsertIntoSymbolTable(symbol_table, symbol, index);
289 }
290 }
291 ASSERT(symbol.IsSymbol());
292 return symbol.raw();
293 } 316 }
294 317
295 318
296 RawString* Symbols::FromCharCode(int32_t char_code) { 319 RawString* Symbols::FromCharCode(int32_t char_code) {
297 if (char_code > kMaxOneCharCodeSymbol) { 320 if (char_code > kMaxOneCharCodeSymbol) {
298 return FromUTF32(&char_code, 1); 321 return FromUTF32(&char_code, 1);
299 } 322 }
300 return predefined_[char_code]; 323 return predefined_[char_code];
301 } 324 }
302 325
303 326
304 void Symbols::DumpStats() { 327 void Symbols::DumpStats() {
305 if (FLAG_dump_symbol_stats) { 328 if (FLAG_dump_symbol_stats) {
306 intptr_t table_size = 0; 329 intptr_t size = -1;
307 dart::Smi& used = Smi::Handle(); 330 intptr_t capacity = -1;
308 Array& symbol_table = Array::Handle(Array::null());
309
310 // First dump VM symbol table stats. 331 // First dump VM symbol table stats.
311 symbol_table = Dart::vm_isolate()->object_store()->symbol_table(); 332 GetStats(Dart::vm_isolate(), &size, &capacity);
312 table_size = symbol_table.Length() - 1; 333 OS::Print("VM Isolate: Number of symbols : %" Pd "\n", size);
313 used ^= symbol_table.At(table_size); 334 OS::Print("VM Isolate: Symbol table capacity : %" Pd "\n", capacity);
314 OS::Print("VM Isolate: Number of symbols : %" Pd "\n", used.Value());
315 OS::Print("VM Isolate: Symbol table capacity : %" Pd "\n", table_size);
316
317 // Now dump regular isolate symbol table stats. 335 // Now dump regular isolate symbol table stats.
318 symbol_table = Isolate::Current()->object_store()->symbol_table(); 336 GetStats(Isolate::Current(), &size, &capacity);
319 table_size = symbol_table.Length() - 1; 337 OS::Print("Isolate: Number of symbols : %" Pd "\n", size);
320 used ^= symbol_table.At(table_size); 338 OS::Print("Isolate: Symbol table capacity : %" Pd "\n", capacity);
321 OS::Print("Isolate: Number of symbols : %" Pd "\n", used.Value()); 339 // TODO(koda): Consider recording growth and collision stats in HashTable,
322 OS::Print("Isolate: Symbol table capacity : %" Pd "\n", table_size); 340 // in DEBUG mode.
323
324 // Dump overall collision and growth counts.
325 OS::Print("Number of symbol table grows = %" Pd "\n", num_of_grows_);
326 OS::Print("Collision counts on add and lookup :\n");
327 intptr_t i = 0;
328 for (i = 0; i < (kMaxCollisionBuckets - 1); i++) {
329 OS::Print(" %" Pd " collisions => %" Pd "\n", i, collision_count_[i]);
330 }
331 OS::Print(" > %" Pd " collisions => %" Pd "\n", i, collision_count_[i]);
332 } 341 }
333 } 342 }
334 343
335 344
336 void Symbols::GrowSymbolTable(const Array& symbol_table) {
337 // TODO(iposva): Avoid exponential growth.
338 num_of_grows_ += 1;
339 intptr_t table_size = symbol_table.Length() - 1;
340 intptr_t new_table_size = table_size * 2;
341 Array& new_symbol_table =
342 Array::Handle(Array::New(new_table_size + 1, Heap::kOld));
343 // Copy all elements from the original symbol table to the newly allocated
344 // array.
345 String& element = String::Handle();
346 dart::Object& new_element = Object::Handle();
347 for (intptr_t i = 0; i < table_size; i++) {
348 element ^= symbol_table.At(i);
349 if (!element.IsNull()) {
350 intptr_t hash = element.Hash();
351 intptr_t index = hash % new_table_size;
352 new_element = new_symbol_table.At(index);
353 intptr_t num_collisions = 0;
354 while (!new_element.IsNull()) {
355 index = (index + 1) % new_table_size; // Move to next element.
356 new_element = new_symbol_table.At(index);
357 num_collisions += 1;
358 }
359 if (FLAG_dump_symbol_stats) {
360 if (num_collisions >= kMaxCollisionBuckets) {
361 num_collisions = (kMaxCollisionBuckets - 1);
362 }
363 collision_count_[num_collisions] += 1;
364 }
365 new_symbol_table.SetAt(index, element);
366 }
367 }
368 // Copy used count.
369 new_element = symbol_table.At(table_size);
370 new_symbol_table.SetAt(new_table_size, new_element);
371 // Remember the new symbol table now.
372 Isolate::Current()->object_store()->set_symbol_table(new_symbol_table);
373 }
374
375
376 void Symbols::InsertIntoSymbolTable(const Array& symbol_table,
377 const String& symbol,
378 intptr_t index) {
379 intptr_t table_size = symbol_table.Length() - 1;
380 symbol.SetCanonical(); // Mark object as being canonical.
381 symbol_table.SetAt(index, symbol); // Remember the new symbol.
382 dart::Smi& used = Smi::Handle();
383 used ^= symbol_table.At(table_size);
384 intptr_t used_elements = used.Value() + 1; // One more element added.
385 used = Smi::New(used_elements);
386 symbol_table.SetAt(table_size, used); // Update used count.
387
388 // Rehash if symbol_table is 75% full.
389 if (used_elements > ((table_size / 4) * 3)) {
390 GrowSymbolTable(symbol_table);
391 }
392 }
393
394
395 template<typename T>
396 intptr_t Symbols::FindIndex(const Array& symbol_table,
397 const T* characters,
398 intptr_t len,
399 intptr_t hash) {
400 // Last element of the array is the number of used elements.
401 intptr_t table_size = symbol_table.Length() - 1;
402 intptr_t index = hash % table_size;
403 intptr_t num_collisions = 0;
404
405 String& symbol = String::Handle();
406 symbol ^= symbol_table.At(index);
407 while (!symbol.IsNull() && !symbol.Equals(characters, len)) {
408 index = (index + 1) % table_size; // Move to next element.
409 symbol ^= symbol_table.At(index);
410 num_collisions += 1;
411 }
412 if (FLAG_dump_symbol_stats) {
413 if (num_collisions >= kMaxCollisionBuckets) {
414 num_collisions = (kMaxCollisionBuckets - 1);
415 }
416 collision_count_[num_collisions] += 1;
417 }
418 return index; // Index of symbol if found or slot into which to add symbol.
419 }
420
421
422 template intptr_t Symbols::FindIndex(const Array& symbol_table,
423 const uint8_t* characters,
424 intptr_t len,
425 intptr_t hash);
426 template intptr_t Symbols::FindIndex(const Array& symbol_table,
427 const uint16_t* characters,
428 intptr_t len,
429 intptr_t hash);
430 template intptr_t Symbols::FindIndex(const Array& symbol_table,
431 const int32_t* characters,
432 intptr_t len,
433 intptr_t hash);
434
435
436 intptr_t Symbols::FindIndex(const Array& symbol_table,
437 const String& str,
438 intptr_t begin_index,
439 intptr_t len,
440 intptr_t hash) {
441 // Last element of the array is the number of used elements.
442 intptr_t table_size = symbol_table.Length() - 1;
443 intptr_t index = hash % table_size;
444 intptr_t num_collisions = 0;
445
446 String& symbol = String::Handle();
447 symbol ^= symbol_table.At(index);
448 while (!symbol.IsNull() && !symbol.Equals(str, begin_index, len)) {
449 index = (index + 1) % table_size; // Move to next element.
450 symbol ^= symbol_table.At(index);
451 num_collisions += 1;
452 }
453 if (FLAG_dump_symbol_stats) {
454 if (num_collisions >= kMaxCollisionBuckets) {
455 num_collisions = (kMaxCollisionBuckets - 1);
456 }
457 collision_count_[num_collisions] += 1;
458 }
459 return index; // Index of symbol if found or slot into which to add symbol.
460 }
461
462
463 intptr_t Symbols::LookupVMSymbol(RawObject* obj) { 345 intptr_t Symbols::LookupVMSymbol(RawObject* obj) {
464 for (intptr_t i = 1; i < Symbols::kMaxPredefinedId; i++) { 346 for (intptr_t i = 1; i < Symbols::kMaxPredefinedId; i++) {
465 if (symbol_handles_[i]->raw() == obj) { 347 if (symbol_handles_[i]->raw() == obj) {
466 return (i + kMaxPredefinedObjectIds); 348 return (i + kMaxPredefinedObjectIds);
467 } 349 }
468 } 350 }
469 return kInvalidIndex; 351 return kInvalidIndex;
470 } 352 }
471 353
472 354
473 RawObject* Symbols::GetVMSymbol(intptr_t object_id) { 355 RawObject* Symbols::GetVMSymbol(intptr_t object_id) {
474 ASSERT(IsVMSymbolId(object_id)); 356 ASSERT(IsVMSymbolId(object_id));
475 intptr_t i = (object_id - kMaxPredefinedObjectIds); 357 intptr_t i = (object_id - kMaxPredefinedObjectIds);
476 if ((i > kIllegal) && (i < Symbols::kMaxPredefinedId)) { 358 if ((i > kIllegal) && (i < Symbols::kMaxPredefinedId)) {
477 return symbol_handles_[i]->raw(); 359 return symbol_handles_[i]->raw();
478 } 360 }
479 return Object::null(); 361 return Object::null();
480 } 362 }
481 363
482 } // namespace dart 364 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/symbols.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698