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