OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include "vm/symbols.h" | |
6 | |
7 #include "vm/isolate.h" | |
8 #include "vm/object.h" | |
9 #include "vm/object_store.h" | |
10 #include "vm/raw_object.h" | |
11 #include "vm/unicode.h" | |
12 #include "vm/visitor.h" | |
13 | |
14 namespace dart { | |
15 | |
16 const char* Symbols::kDot = "."; | |
17 RawString* Symbols::dot_ = String::null(); | |
18 | |
19 | |
20 void Symbols::Init(Isolate* isolate) { | |
Ivan Posva
2012/07/23 18:26:34
Maybe name this InitOnce to make it clearer?
siva
2012/07/23 23:09:00
Done.
| |
21 // Should only be run by the vm isolate. | |
22 ASSERT(isolate == Dart::vm_isolate()); | |
23 | |
24 // Pre-allocate the Array and OneByteString class in the vm isolate so that | |
Ivan Posva
2012/07/23 18:26:34
How about turning this around? These two need to b
siva
2012/07/23 23:09:00
Done.
| |
25 // we can create a symbol table and populate it with some frequently used | |
26 // strings as symbols. | |
27 const Class& cls = Class::Handle(Class::New<Array>()); | |
28 isolate->object_store()->set_array_class(cls); | |
29 Class::New<OneByteString>(); | |
30 isolate->object_store()->set_one_byte_string_class(cls); | |
31 | |
32 // Create and setup a symbol table in the vm isolate. | |
33 SetupSymbolTable(isolate); | |
34 | |
35 // Create all predefined symbols. | |
36 const Array& symbol_table = | |
37 Array::Handle(isolate->object_store()->symbol_table()); | |
38 OneByteString& str = OneByteString::Handle(); | |
39 | |
40 str = OneByteString::New(kDot, Heap::kOld); | |
41 Add(symbol_table, str); // "." | |
42 dot_ = str.raw(); | |
43 } | |
44 | |
45 | |
46 void Symbols::SetupSymbolTable(Isolate* isolate) { | |
47 ASSERT(isolate != NULL); | |
48 | |
49 // Setup the symbol table used within the String class. | |
50 const Array& array = Array::Handle(Array::New(kInitialSymbolTableSize + 1)); | |
51 | |
52 // Last element contains the count of used slots. | |
53 array.SetAt(kInitialSymbolTableSize, Smi::Handle(Smi::New(0))); | |
54 isolate->object_store()->set_symbol_table(array); | |
55 } | |
56 | |
57 | |
58 void Symbols::Add(const Array& symbol_table, const String& str) { | |
59 // Should only be run by the vm isolate. | |
60 ASSERT(Isolate::Current() == Dart::vm_isolate()); | |
61 intptr_t hash = str.Hash(); | |
62 intptr_t index = FindIndex(symbol_table, str, 0, str.Length(), hash); | |
63 ASSERT(symbol_table.At(index) == String::null()); | |
64 InsertIntoSymbolTable(symbol_table, str, index); | |
65 } | |
66 | |
67 | |
68 RawString* Symbols::New(const char* str) { | |
69 intptr_t width = 0; | |
70 intptr_t len = Utf8::CodePointCount(str, &width); | |
71 intptr_t size = len * width; | |
72 Zone* zone = Isolate::Current()->current_zone(); | |
73 if (len == 0) { | |
74 return Symbols::New(reinterpret_cast<uint8_t*>(NULL), 0); | |
75 } else if (width == 1) { | |
76 uint8_t* characters = reinterpret_cast<uint8_t*>(zone->Allocate(size)); | |
77 Utf8::Decode(str, characters, len); | |
78 return New(characters, len); | |
79 } else if (width == 2) { | |
80 uint16_t* characters = reinterpret_cast<uint16_t*>(zone->Allocate(size)); | |
81 Utf8::Decode(str, characters, len); | |
82 return New(characters, len); | |
83 } | |
84 ASSERT(width == 4); | |
85 uint32_t* characters = reinterpret_cast<uint32_t*>(zone->Allocate(size)); | |
86 Utf8::Decode(str, characters, len); | |
87 return New(characters, len); | |
88 } | |
89 | |
90 | |
91 template<typename T> | |
92 RawString* Symbols::New(const T* characters, intptr_t len) { | |
93 Isolate* isolate = Isolate::Current(); | |
94 ASSERT(isolate != Dart::vm_isolate()); | |
95 String& symbol = String::Handle(isolate, String::null()); | |
96 Array& symbol_table = Array::Handle(isolate, Array::null()); | |
97 | |
98 // Calculate the String hash for this sequence of characters. | |
99 intptr_t hash = String::Hash(characters, len); | |
100 | |
101 // First check if a symbol exists in the vm isolate for these characters. | |
102 symbol_table = Dart::vm_isolate()->object_store()->symbol_table(); | |
103 intptr_t index = FindIndex(symbol_table, characters, len, hash); | |
104 symbol ^= symbol_table.At(index); | |
105 if (symbol.IsNull()) { | |
106 // Now try in the symbol table of the current isolate. | |
107 symbol_table = isolate->object_store()->symbol_table(); | |
108 index = FindIndex(symbol_table, characters, len, hash); | |
109 // Since we leave enough room in the table to guarantee, that we find an | |
110 // empty spot, index is the insertion point if symbol is null. | |
111 symbol ^= symbol_table.At(index); | |
112 if (symbol.IsNull()) { | |
113 // Allocate new result string. | |
114 symbol = String::New(characters, len, Heap::kOld); | |
115 symbol.SetHash(hash); // Remember the calculated hash value. | |
116 InsertIntoSymbolTable(symbol_table, symbol, index); | |
117 } | |
118 } | |
119 ASSERT(symbol.IsSymbol()); | |
120 return symbol.raw(); | |
121 } | |
122 | |
123 template RawString* Symbols::New(const uint8_t* characters, intptr_t len); | |
124 template RawString* Symbols::New(const uint16_t* characters, intptr_t len); | |
125 template RawString* Symbols::New(const uint32_t* characters, intptr_t len); | |
126 | |
127 | |
128 RawString* Symbols::New(const String& str) { | |
129 if (str.IsSymbol()) { | |
130 return str.raw(); | |
131 } | |
132 return New(str, 0, str.Length()); | |
133 } | |
134 | |
135 | |
136 RawString* Symbols::New(const String& str, intptr_t begin_index, intptr_t len) { | |
137 ASSERT(begin_index >= 0); | |
138 ASSERT(len >= 0); | |
139 ASSERT((begin_index + len) <= str.Length()); | |
140 Isolate* isolate = Isolate::Current(); | |
141 ASSERT(isolate != Dart::vm_isolate()); | |
142 String& symbol = String::Handle(isolate, String::null()); | |
143 Array& symbol_table = Array::Handle(isolate, Array::null()); | |
144 | |
145 // Calculate the String hash for this sequence of characters. | |
146 intptr_t hash = (begin_index == 0 && len == str.Length()) ? str.Hash() : | |
147 String::Hash(str, begin_index, len); | |
148 | |
149 // First check if a symbol exists in the vm isolate for these characters. | |
150 symbol_table = Dart::vm_isolate()->object_store()->symbol_table(); | |
151 intptr_t index = FindIndex(symbol_table, str, begin_index, len, hash); | |
152 symbol ^= symbol_table.At(index); | |
153 if (symbol.IsNull()) { | |
154 // Now try in the symbol table of the current isolate. | |
155 symbol_table = isolate->object_store()->symbol_table(); | |
156 index = FindIndex(symbol_table, str, begin_index, len, hash); | |
157 // Since we leave enough room in the table to guarantee, that we find an | |
158 // empty spot, index is the insertion point if symbol is null. | |
159 symbol ^= symbol_table.At(index); | |
160 if (symbol.IsNull()) { | |
161 if (str.IsOld() && begin_index == 0 && len == str.Length()) { | |
162 // Reuse the incoming str as the symbol value. | |
163 symbol = str.raw(); | |
164 } else { | |
165 // Allocate a copy in old space. | |
166 symbol = String::SubString(str, begin_index, len, Heap::kOld); | |
167 symbol.SetHash(hash); | |
168 } | |
169 InsertIntoSymbolTable(symbol_table, symbol, index); | |
170 } | |
171 } | |
172 ASSERT(symbol.IsSymbol()); | |
173 return symbol.raw(); | |
174 } | |
175 | |
176 | |
177 void Symbols::GrowSymbolTable(const Array& symbol_table) { | |
178 // TODO(iposva): Avoid exponential growth. | |
179 intptr_t table_size = symbol_table.Length() - 1; | |
180 intptr_t new_table_size = table_size * 2; | |
181 Array& new_symbol_table = Array::Handle(Array::New(new_table_size + 1)); | |
182 // Copy all elements from the original symbol table to the newly allocated | |
183 // array. | |
184 String& element = String::Handle(); | |
185 Object& new_element = Object::Handle(); | |
186 for (intptr_t i = 0; i < table_size; i++) { | |
187 element ^= symbol_table.At(i); | |
188 if (!element.IsNull()) { | |
189 intptr_t hash = element.Hash(); | |
190 intptr_t index = hash % new_table_size; | |
191 new_element = new_symbol_table.At(index); | |
192 while (!new_element.IsNull()) { | |
193 index = (index + 1) % new_table_size; // Move to next element. | |
194 new_element = new_symbol_table.At(index); | |
195 } | |
196 new_symbol_table.SetAt(index, element); | |
197 } | |
198 } | |
199 // Copy used count. | |
200 new_element = symbol_table.At(table_size); | |
201 new_symbol_table.SetAt(new_table_size, new_element); | |
202 // Remember the new symbol table now. | |
203 Isolate::Current()->object_store()->set_symbol_table(new_symbol_table); | |
204 } | |
205 | |
206 | |
207 void Symbols::InsertIntoSymbolTable(const Array& symbol_table, | |
208 const String& symbol, | |
209 intptr_t index) { | |
210 intptr_t table_size = symbol_table.Length() - 1; | |
211 symbol.SetCanonical(); // Mark object as being canonical. | |
212 symbol_table.SetAt(index, symbol); // Remember the new symbol. | |
213 Smi& used = Smi::Handle(); | |
214 used ^= symbol_table.At(table_size); | |
215 intptr_t used_elements = used.Value() + 1; // One more element added. | |
216 used = Smi::New(used_elements); | |
217 symbol_table.SetAt(table_size, used); // Update used count. | |
218 | |
219 // Rehash if symbol_table is 75% full. | |
220 if (used_elements > ((table_size / 4) * 3)) { | |
221 GrowSymbolTable(symbol_table); | |
222 } | |
223 } | |
224 | |
225 | |
226 template<typename T> | |
227 intptr_t Symbols::FindIndex(const Array& symbol_table, | |
228 const T* characters, | |
229 intptr_t len, | |
230 intptr_t hash) { | |
231 // Last element of the array is the number of used elements. | |
232 intptr_t table_size = symbol_table.Length() - 1; | |
233 intptr_t index = hash % table_size; | |
234 | |
235 String& symbol = String::Handle(); | |
236 symbol ^= symbol_table.At(index); | |
237 while (!symbol.IsNull() && !symbol.Equals(characters, len)) { | |
238 index = (index + 1) % table_size; // Move to next element. | |
239 symbol ^= symbol_table.At(index); | |
240 } | |
241 return index; // Index of symbol if found or slot into which to add symbol. | |
242 } | |
243 | |
244 | |
245 template intptr_t Symbols::FindIndex(const Array& symbol_table, | |
246 const uint8_t* characters, | |
247 intptr_t len, | |
248 intptr_t hash); | |
249 template intptr_t Symbols::FindIndex(const Array& symbol_table, | |
250 const uint16_t* characters, | |
251 intptr_t len, | |
252 intptr_t hash); | |
253 template intptr_t Symbols::FindIndex(const Array& symbol_table, | |
254 const uint32_t* characters, | |
255 intptr_t len, | |
256 intptr_t hash); | |
257 | |
258 | |
259 intptr_t Symbols::FindIndex(const Array& symbol_table, | |
260 const String& str, | |
261 intptr_t begin_index, | |
262 intptr_t len, | |
263 intptr_t hash) { | |
264 // Last element of the array is the number of used elements. | |
265 intptr_t table_size = symbol_table.Length() - 1; | |
266 intptr_t index = hash % table_size; | |
267 | |
268 String& symbol = String::Handle(); | |
269 symbol ^= symbol_table.At(index); | |
270 while (!symbol.IsNull() && !symbol.Equals(str, begin_index, len)) { | |
271 index = (index + 1) % table_size; // Move to next element. | |
272 symbol ^= symbol_table.At(index); | |
273 } | |
274 return index; // Index of symbol if found or slot into which to add symbol. | |
275 } | |
276 | |
277 } // namespace dart | |
OLD | NEW |