2012-07-24 00:01:50 +00:00
|
|
|
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "vm/symbols.h"
|
|
|
|
|
2012-12-10 18:24:34 +00:00
|
|
|
#include "vm/handles.h"
|
|
|
|
#include "vm/handles_impl.h"
|
2012-07-24 00:01:50 +00:00
|
|
|
#include "vm/isolate.h"
|
|
|
|
#include "vm/object.h"
|
|
|
|
#include "vm/object_store.h"
|
|
|
|
#include "vm/raw_object.h"
|
2012-08-08 19:46:23 +00:00
|
|
|
#include "vm/snapshot_ids.h"
|
2012-07-24 00:01:50 +00:00
|
|
|
#include "vm/unicode.h"
|
|
|
|
#include "vm/visitor.h"
|
|
|
|
|
|
|
|
namespace dart {
|
|
|
|
|
2013-01-02 19:31:59 +00:00
|
|
|
RawString* Symbols::predefined_[Symbols::kNumberOfOneCharCodeSymbols];
|
|
|
|
String* Symbols::symbol_handles_[Symbols::kMaxPredefinedId];
|
2012-07-25 20:31:26 +00:00
|
|
|
|
|
|
|
static const char* names[] = {
|
|
|
|
NULL,
|
|
|
|
|
|
|
|
#define DEFINE_SYMBOL_LITERAL(symbol, literal) \
|
|
|
|
literal,
|
|
|
|
PREDEFINED_SYMBOLS_LIST(DEFINE_SYMBOL_LITERAL)
|
|
|
|
#undef DEFINE_SYMBOL_LITERAL
|
2013-11-14 19:14:16 +00:00
|
|
|
|
|
|
|
"", // matches kKwTableStart.
|
|
|
|
|
|
|
|
#define DEFINE_KEYWORD_SYMBOL_INDEX(token, chars, ignore1, ignore2) \
|
|
|
|
chars,
|
|
|
|
DART_KEYWORD_LIST(DEFINE_KEYWORD_SYMBOL_INDEX)
|
|
|
|
#undef DEFINE_KEYWORD_SYMBOL_INDEX
|
2012-07-25 20:31:26 +00:00
|
|
|
};
|
2012-07-24 00:01:50 +00:00
|
|
|
|
2012-12-12 00:35:48 +00:00
|
|
|
intptr_t Symbols::num_of_grows_;
|
|
|
|
intptr_t Symbols::collision_count_[kMaxCollisionBuckets];
|
|
|
|
|
|
|
|
DEFINE_FLAG(bool, dump_symbol_stats, false, "Dump symbol table statistics");
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
|
2012-11-19 16:06:19 +00:00
|
|
|
const char* Symbols::Name(SymbolId symbol) {
|
2013-01-02 19:31:59 +00:00
|
|
|
ASSERT((symbol > kIllegal) && (symbol < kNullCharId));
|
2012-08-30 22:46:44 +00:00
|
|
|
return names[symbol];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-14 19:14:16 +00:00
|
|
|
const String& Symbols::Keyword(Token::Kind keyword) {
|
|
|
|
const int kw_index = keyword - Token::kFirstKeyword;
|
2014-06-03 20:14:24 +00:00
|
|
|
ASSERT((0 <= kw_index) && (kw_index < Token::kNumKeywords));
|
2013-11-14 22:19:23 +00:00
|
|
|
// First keyword symbol is in symbol_handles_[kKwTableStart + 1].
|
|
|
|
const intptr_t keyword_id = Symbols::kKwTableStart + 1 + kw_index;
|
2013-11-14 19:14:16 +00:00
|
|
|
ASSERT(symbol_handles_[keyword_id] != NULL);
|
|
|
|
return *symbol_handles_[keyword_id];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
void Symbols::InitOnce(Isolate* isolate) {
|
|
|
|
// Should only be run by the vm isolate.
|
|
|
|
ASSERT(isolate == Dart::vm_isolate());
|
|
|
|
|
2012-12-12 00:35:48 +00:00
|
|
|
if (FLAG_dump_symbol_stats) {
|
|
|
|
num_of_grows_ = 0;
|
|
|
|
for (intptr_t i = 0; i < kMaxCollisionBuckets; i++) {
|
|
|
|
collision_count_[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
// Create and setup a symbol table in the vm isolate.
|
|
|
|
SetupSymbolTable(isolate);
|
|
|
|
|
|
|
|
// Create all predefined symbols.
|
2013-01-02 19:31:59 +00:00
|
|
|
ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kNullCharId);
|
2012-11-15 09:15:14 +00:00
|
|
|
ObjectStore* object_store = isolate->object_store();
|
|
|
|
Array& symbol_table = Array::Handle();
|
2012-07-24 00:01:50 +00:00
|
|
|
|
2013-01-02 19:31:59 +00:00
|
|
|
|
|
|
|
// First set up all the predefined string symbols.
|
2013-11-14 19:14:16 +00:00
|
|
|
for (intptr_t i = 1; i < Symbols::kKwTableStart; i++) {
|
2012-11-15 09:15:14 +00:00
|
|
|
// The symbol_table needs to be reloaded as it might have grown in the
|
|
|
|
// previous iteration.
|
|
|
|
symbol_table = object_store->symbol_table();
|
2013-05-30 01:24:09 +00:00
|
|
|
String* str = String::ReadOnlyHandle();
|
2013-01-02 19:31:59 +00:00
|
|
|
*str = OneByteString::New(names[i], Heap::kOld);
|
|
|
|
Add(symbol_table, *str);
|
|
|
|
symbol_handles_[i] = str;
|
2012-07-25 20:31:26 +00:00
|
|
|
}
|
2012-08-10 21:43:00 +00:00
|
|
|
Object::RegisterSingletonClassNames();
|
2012-11-19 16:06:19 +00:00
|
|
|
|
2013-11-14 19:14:16 +00:00
|
|
|
// Create symbols for language keywords. Some keywords are equal to
|
|
|
|
// symbols we already created, so use New() instead of Add() to ensure
|
|
|
|
// that the symbols are canonicalized.
|
|
|
|
for (intptr_t i = Symbols::kKwTableStart; i < Symbols::kNullCharId; i++) {
|
|
|
|
String* str = String::ReadOnlyHandle();
|
|
|
|
*str = New(names[i]);
|
|
|
|
symbol_handles_[i] = str;
|
|
|
|
}
|
|
|
|
|
2012-12-21 03:07:10 +00:00
|
|
|
// Add Latin1 characters as Symbols, so that Symbols::FromCharCode is fast.
|
2013-01-02 19:31:59 +00:00
|
|
|
for (intptr_t c = 0; c < kNumberOfOneCharCodeSymbols; c++) {
|
2012-12-21 03:07:10 +00:00
|
|
|
// The symbol_table needs to be reloaded as it might have grown in the
|
|
|
|
// previous iteration.
|
|
|
|
symbol_table = object_store->symbol_table();
|
2013-01-02 19:31:59 +00:00
|
|
|
intptr_t idx = (kNullCharId + c);
|
|
|
|
ASSERT(idx < kMaxPredefinedId);
|
2012-12-21 03:07:10 +00:00
|
|
|
ASSERT(Utf::IsLatin1(c));
|
|
|
|
uint8_t ch = static_cast<uint8_t>(c);
|
2013-05-30 01:24:09 +00:00
|
|
|
String* str = String::ReadOnlyHandle();
|
2013-01-02 19:31:59 +00:00
|
|
|
*str = OneByteString::New(&ch, 1, Heap::kOld);
|
|
|
|
Add(symbol_table, *str);
|
|
|
|
predefined_[c] = str->raw();
|
|
|
|
symbol_handles_[idx] = str;
|
2012-11-19 16:06:19 +00:00
|
|
|
}
|
2012-07-24 00:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Symbols::SetupSymbolTable(Isolate* isolate) {
|
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
|
|
|
|
// Setup the symbol table used within the String class.
|
2013-10-08 18:54:00 +00:00
|
|
|
const intptr_t initial_size = (isolate == Dart::vm_isolate()) ?
|
2012-07-25 20:31:26 +00:00
|
|
|
kInitialVMIsolateSymtabSize : kInitialSymtabSize;
|
2014-04-23 22:48:33 +00:00
|
|
|
const Array& array = Array::Handle(Array::New(initial_size + 1, Heap::kOld));
|
2012-07-24 00:01:50 +00:00
|
|
|
|
|
|
|
// Last element contains the count of used slots.
|
2012-07-25 20:31:26 +00:00
|
|
|
array.SetAt(initial_size, Smi::Handle(Smi::New(0)));
|
2012-07-24 00:01:50 +00:00
|
|
|
isolate->object_store()->set_symbol_table(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 23:41:53 +00:00
|
|
|
intptr_t Symbols::Size(Isolate* isolate) {
|
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
Array& symbol_table = Array::Handle(isolate,
|
|
|
|
isolate->object_store()->symbol_table());
|
|
|
|
intptr_t table_size_index = symbol_table.Length() - 1;
|
2012-08-16 17:36:41 +00:00
|
|
|
dart::Smi& used = Smi::Handle();
|
2013-01-23 20:01:31 +00:00
|
|
|
used ^= symbol_table.At(table_size_index);
|
2012-07-25 23:41:53 +00:00
|
|
|
return used.Value();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
void Symbols::Add(const Array& symbol_table, const String& str) {
|
|
|
|
// Should only be run by the vm isolate.
|
|
|
|
ASSERT(Isolate::Current() == Dart::vm_isolate());
|
|
|
|
intptr_t hash = str.Hash();
|
|
|
|
intptr_t index = FindIndex(symbol_table, str, 0, str.Length(), hash);
|
|
|
|
ASSERT(symbol_table.At(index) == String::null());
|
|
|
|
InsertIntoSymbolTable(symbol_table, str, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-13 23:09:22 +00:00
|
|
|
RawString* Symbols::New(const char* cstr, intptr_t len) {
|
|
|
|
ASSERT((cstr != NULL) && (len >= 0));
|
2012-12-04 22:18:12 +00:00
|
|
|
const uint8_t* utf8_array = reinterpret_cast<const uint8_t*>(cstr);
|
2014-05-13 23:09:22 +00:00
|
|
|
return Symbols::FromUTF8(utf8_array, len);
|
2012-12-04 22:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawString* Symbols::FromUTF8(const uint8_t* utf8_array, intptr_t array_len) {
|
|
|
|
if (array_len == 0 || utf8_array == NULL) {
|
2012-12-05 23:37:37 +00:00
|
|
|
return FromLatin1(reinterpret_cast<uint8_t*>(NULL), 0);
|
2012-12-04 22:18:12 +00:00
|
|
|
}
|
2012-10-31 17:56:46 +00:00
|
|
|
Utf8::Type type;
|
2012-12-04 22:18:12 +00:00
|
|
|
intptr_t len = Utf8::CodeUnitCount(utf8_array, array_len, &type);
|
|
|
|
ASSERT(len != 0);
|
2012-10-16 22:05:40 +00:00
|
|
|
Zone* zone = Isolate::Current()->current_zone();
|
2012-11-16 00:13:18 +00:00
|
|
|
if (type == Utf8::kLatin1) {
|
2012-08-03 21:51:44 +00:00
|
|
|
uint8_t* characters = zone->Alloc<uint8_t>(len);
|
2012-12-04 22:18:12 +00:00
|
|
|
Utf8::DecodeToLatin1(utf8_array, array_len, characters, len);
|
2012-12-05 23:37:37 +00:00
|
|
|
return FromLatin1(characters, len);
|
2012-07-24 00:01:50 +00:00
|
|
|
}
|
2012-11-20 02:37:21 +00:00
|
|
|
ASSERT((type == Utf8::kBMP) || (type == Utf8::kSupplementary));
|
2012-10-31 17:56:46 +00:00
|
|
|
uint16_t* characters = zone->Alloc<uint16_t>(len);
|
2012-12-04 22:18:12 +00:00
|
|
|
Utf8::DecodeToUTF16(utf8_array, array_len, characters, len);
|
2012-12-05 23:37:37 +00:00
|
|
|
return FromUTF16(characters, len);
|
2012-12-04 22:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawString* Symbols::FromLatin1(const uint8_t* latin1_array, intptr_t len) {
|
2012-12-05 23:37:37 +00:00
|
|
|
return NewSymbol(latin1_array, len, String::FromLatin1);
|
2012-12-04 22:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawString* Symbols::FromUTF16(const uint16_t* utf16_array, intptr_t len) {
|
2012-12-05 23:37:37 +00:00
|
|
|
return NewSymbol(utf16_array, len, String::FromUTF16);
|
2012-12-04 22:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawString* Symbols::FromUTF32(const int32_t* utf32_array, intptr_t len) {
|
2012-12-05 23:37:37 +00:00
|
|
|
return NewSymbol(utf32_array, len, String::FromUTF32);
|
2012-07-24 00:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-05 23:37:37 +00:00
|
|
|
template<typename CharacterType, typename CallbackType>
|
|
|
|
RawString* Symbols::NewSymbol(const CharacterType* characters,
|
|
|
|
intptr_t len,
|
|
|
|
CallbackType new_string) {
|
2012-07-24 00:01:50 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
String& symbol = String::Handle(isolate, String::null());
|
|
|
|
Array& symbol_table = Array::Handle(isolate, Array::null());
|
|
|
|
|
|
|
|
// Calculate the String hash for this sequence of characters.
|
|
|
|
intptr_t hash = String::Hash(characters, len);
|
|
|
|
|
|
|
|
// First check if a symbol exists in the vm isolate for these characters.
|
|
|
|
symbol_table = Dart::vm_isolate()->object_store()->symbol_table();
|
|
|
|
intptr_t index = FindIndex(symbol_table, characters, len, hash);
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-07-24 00:01:50 +00:00
|
|
|
if (symbol.IsNull()) {
|
|
|
|
// Now try in the symbol table of the current isolate.
|
|
|
|
symbol_table = isolate->object_store()->symbol_table();
|
|
|
|
index = FindIndex(symbol_table, characters, len, hash);
|
|
|
|
// Since we leave enough room in the table to guarantee, that we find an
|
|
|
|
// empty spot, index is the insertion point if symbol is null.
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-07-24 00:01:50 +00:00
|
|
|
if (symbol.IsNull()) {
|
|
|
|
// Allocate new result string.
|
2012-12-05 23:37:37 +00:00
|
|
|
symbol = (*new_string)(characters, len, Heap::kOld);
|
2012-07-24 00:01:50 +00:00
|
|
|
symbol.SetHash(hash); // Remember the calculated hash value.
|
|
|
|
InsertIntoSymbolTable(symbol_table, symbol, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(symbol.IsSymbol());
|
|
|
|
return symbol.raw();
|
|
|
|
}
|
|
|
|
|
2012-12-04 22:18:12 +00:00
|
|
|
|
|
|
|
template RawString* Symbols::NewSymbol(const uint8_t* characters,
|
2012-12-05 23:37:37 +00:00
|
|
|
intptr_t len,
|
|
|
|
RawString* (*new_string)(const uint8_t*,
|
|
|
|
intptr_t,
|
|
|
|
Heap::Space));
|
2012-12-04 22:18:12 +00:00
|
|
|
template RawString* Symbols::NewSymbol(const uint16_t* characters,
|
2012-12-05 23:37:37 +00:00
|
|
|
intptr_t len,
|
|
|
|
RawString* (*new_string)(const uint16_t*,
|
|
|
|
intptr_t,
|
|
|
|
Heap::Space));
|
2012-12-04 22:18:12 +00:00
|
|
|
template RawString* Symbols::NewSymbol(const int32_t* characters,
|
2012-12-05 23:37:37 +00:00
|
|
|
intptr_t len,
|
|
|
|
RawString* (*new_string)(const int32_t*,
|
|
|
|
intptr_t,
|
|
|
|
Heap::Space));
|
2012-07-24 00:01:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
RawString* Symbols::New(const String& str) {
|
|
|
|
if (str.IsSymbol()) {
|
|
|
|
return str.raw();
|
|
|
|
}
|
|
|
|
return New(str, 0, str.Length());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawString* Symbols::New(const String& str, intptr_t begin_index, intptr_t len) {
|
|
|
|
ASSERT(begin_index >= 0);
|
|
|
|
ASSERT(len >= 0);
|
|
|
|
ASSERT((begin_index + len) <= str.Length());
|
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
ASSERT(isolate != Dart::vm_isolate());
|
|
|
|
String& symbol = String::Handle(isolate, String::null());
|
|
|
|
Array& symbol_table = Array::Handle(isolate, Array::null());
|
|
|
|
|
|
|
|
// Calculate the String hash for this sequence of characters.
|
|
|
|
intptr_t hash = (begin_index == 0 && len == str.Length()) ? str.Hash() :
|
|
|
|
String::Hash(str, begin_index, len);
|
|
|
|
|
|
|
|
// First check if a symbol exists in the vm isolate for these characters.
|
|
|
|
symbol_table = Dart::vm_isolate()->object_store()->symbol_table();
|
|
|
|
intptr_t index = FindIndex(symbol_table, str, begin_index, len, hash);
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-07-24 00:01:50 +00:00
|
|
|
if (symbol.IsNull()) {
|
|
|
|
// Now try in the symbol table of the current isolate.
|
|
|
|
symbol_table = isolate->object_store()->symbol_table();
|
|
|
|
index = FindIndex(symbol_table, str, begin_index, len, hash);
|
|
|
|
// Since we leave enough room in the table to guarantee, that we find an
|
|
|
|
// empty spot, index is the insertion point if symbol is null.
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-07-24 00:01:50 +00:00
|
|
|
if (symbol.IsNull()) {
|
|
|
|
if (str.IsOld() && begin_index == 0 && len == str.Length()) {
|
|
|
|
// Reuse the incoming str as the symbol value.
|
|
|
|
symbol = str.raw();
|
|
|
|
} else {
|
|
|
|
// Allocate a copy in old space.
|
|
|
|
symbol = String::SubString(str, begin_index, len, Heap::kOld);
|
|
|
|
symbol.SetHash(hash);
|
|
|
|
}
|
|
|
|
InsertIntoSymbolTable(symbol_table, symbol, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(symbol.IsSymbol());
|
|
|
|
return symbol.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-21 00:30:27 +00:00
|
|
|
RawString* Symbols::FromCharCode(int32_t char_code) {
|
2012-11-19 16:06:19 +00:00
|
|
|
if (char_code > kMaxOneCharCodeSymbol) {
|
2012-12-04 22:18:12 +00:00
|
|
|
return FromUTF32(&char_code, 1);
|
2012-11-19 16:06:19 +00:00
|
|
|
}
|
2013-01-02 19:31:59 +00:00
|
|
|
return predefined_[char_code];
|
2012-11-19 16:06:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-12 00:35:48 +00:00
|
|
|
void Symbols::DumpStats() {
|
|
|
|
if (FLAG_dump_symbol_stats) {
|
|
|
|
intptr_t table_size = 0;
|
|
|
|
dart::Smi& used = Smi::Handle();
|
|
|
|
Array& symbol_table = Array::Handle(Array::null());
|
|
|
|
|
|
|
|
// First dump VM symbol table stats.
|
|
|
|
symbol_table = Dart::vm_isolate()->object_store()->symbol_table();
|
|
|
|
table_size = symbol_table.Length() - 1;
|
2013-01-23 20:01:31 +00:00
|
|
|
used ^= symbol_table.At(table_size);
|
2013-08-20 20:24:11 +00:00
|
|
|
OS::Print("VM Isolate: Number of symbols : %" Pd "\n", used.Value());
|
|
|
|
OS::Print("VM Isolate: Symbol table capacity : %" Pd "\n", table_size);
|
2012-12-12 00:35:48 +00:00
|
|
|
|
|
|
|
// Now dump regular isolate symbol table stats.
|
|
|
|
symbol_table = Isolate::Current()->object_store()->symbol_table();
|
|
|
|
table_size = symbol_table.Length() - 1;
|
2013-01-23 20:01:31 +00:00
|
|
|
used ^= symbol_table.At(table_size);
|
2013-08-20 20:24:11 +00:00
|
|
|
OS::Print("Isolate: Number of symbols : %" Pd "\n", used.Value());
|
|
|
|
OS::Print("Isolate: Symbol table capacity : %" Pd "\n", table_size);
|
2012-12-12 00:35:48 +00:00
|
|
|
|
|
|
|
// Dump overall collision and growth counts.
|
2013-08-20 20:24:11 +00:00
|
|
|
OS::Print("Number of symbol table grows = %" Pd "\n", num_of_grows_);
|
2012-12-12 00:35:48 +00:00
|
|
|
OS::Print("Collision counts on add and lookup :\n");
|
|
|
|
intptr_t i = 0;
|
|
|
|
for (i = 0; i < (kMaxCollisionBuckets - 1); i++) {
|
2013-08-20 20:24:11 +00:00
|
|
|
OS::Print(" %" Pd " collisions => %" Pd "\n", i, collision_count_[i]);
|
2012-12-12 00:35:48 +00:00
|
|
|
}
|
2013-08-20 20:24:11 +00:00
|
|
|
OS::Print(" > %" Pd " collisions => %" Pd "\n", i, collision_count_[i]);
|
2012-12-12 00:35:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
void Symbols::GrowSymbolTable(const Array& symbol_table) {
|
|
|
|
// TODO(iposva): Avoid exponential growth.
|
2012-12-12 00:35:48 +00:00
|
|
|
num_of_grows_ += 1;
|
2012-07-24 00:01:50 +00:00
|
|
|
intptr_t table_size = symbol_table.Length() - 1;
|
|
|
|
intptr_t new_table_size = table_size * 2;
|
2014-04-23 22:48:33 +00:00
|
|
|
Array& new_symbol_table =
|
|
|
|
Array::Handle(Array::New(new_table_size + 1, Heap::kOld));
|
2012-07-24 00:01:50 +00:00
|
|
|
// Copy all elements from the original symbol table to the newly allocated
|
|
|
|
// array.
|
|
|
|
String& element = String::Handle();
|
2012-08-16 17:36:41 +00:00
|
|
|
dart::Object& new_element = Object::Handle();
|
2012-07-24 00:01:50 +00:00
|
|
|
for (intptr_t i = 0; i < table_size; i++) {
|
2013-01-23 20:01:31 +00:00
|
|
|
element ^= symbol_table.At(i);
|
2012-07-24 00:01:50 +00:00
|
|
|
if (!element.IsNull()) {
|
|
|
|
intptr_t hash = element.Hash();
|
|
|
|
intptr_t index = hash % new_table_size;
|
|
|
|
new_element = new_symbol_table.At(index);
|
2012-12-12 00:35:48 +00:00
|
|
|
intptr_t num_collisions = 0;
|
2012-07-24 00:01:50 +00:00
|
|
|
while (!new_element.IsNull()) {
|
|
|
|
index = (index + 1) % new_table_size; // Move to next element.
|
|
|
|
new_element = new_symbol_table.At(index);
|
2012-12-12 00:35:48 +00:00
|
|
|
num_collisions += 1;
|
|
|
|
}
|
|
|
|
if (FLAG_dump_symbol_stats) {
|
|
|
|
if (num_collisions >= kMaxCollisionBuckets) {
|
|
|
|
num_collisions = (kMaxCollisionBuckets - 1);
|
|
|
|
}
|
|
|
|
collision_count_[num_collisions] += 1;
|
2012-07-24 00:01:50 +00:00
|
|
|
}
|
|
|
|
new_symbol_table.SetAt(index, element);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Copy used count.
|
|
|
|
new_element = symbol_table.At(table_size);
|
|
|
|
new_symbol_table.SetAt(new_table_size, new_element);
|
|
|
|
// Remember the new symbol table now.
|
|
|
|
Isolate::Current()->object_store()->set_symbol_table(new_symbol_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Symbols::InsertIntoSymbolTable(const Array& symbol_table,
|
|
|
|
const String& symbol,
|
|
|
|
intptr_t index) {
|
|
|
|
intptr_t table_size = symbol_table.Length() - 1;
|
|
|
|
symbol.SetCanonical(); // Mark object as being canonical.
|
|
|
|
symbol_table.SetAt(index, symbol); // Remember the new symbol.
|
2012-08-16 17:36:41 +00:00
|
|
|
dart::Smi& used = Smi::Handle();
|
2013-01-23 20:01:31 +00:00
|
|
|
used ^= symbol_table.At(table_size);
|
2012-07-24 00:01:50 +00:00
|
|
|
intptr_t used_elements = used.Value() + 1; // One more element added.
|
|
|
|
used = Smi::New(used_elements);
|
|
|
|
symbol_table.SetAt(table_size, used); // Update used count.
|
|
|
|
|
|
|
|
// Rehash if symbol_table is 75% full.
|
|
|
|
if (used_elements > ((table_size / 4) * 3)) {
|
|
|
|
GrowSymbolTable(symbol_table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
intptr_t Symbols::FindIndex(const Array& symbol_table,
|
|
|
|
const T* characters,
|
|
|
|
intptr_t len,
|
|
|
|
intptr_t hash) {
|
|
|
|
// Last element of the array is the number of used elements.
|
|
|
|
intptr_t table_size = symbol_table.Length() - 1;
|
|
|
|
intptr_t index = hash % table_size;
|
2012-12-12 00:35:48 +00:00
|
|
|
intptr_t num_collisions = 0;
|
2012-07-24 00:01:50 +00:00
|
|
|
|
|
|
|
String& symbol = String::Handle();
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-07-24 00:01:50 +00:00
|
|
|
while (!symbol.IsNull() && !symbol.Equals(characters, len)) {
|
|
|
|
index = (index + 1) % table_size; // Move to next element.
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-12-12 00:35:48 +00:00
|
|
|
num_collisions += 1;
|
|
|
|
}
|
|
|
|
if (FLAG_dump_symbol_stats) {
|
|
|
|
if (num_collisions >= kMaxCollisionBuckets) {
|
|
|
|
num_collisions = (kMaxCollisionBuckets - 1);
|
|
|
|
}
|
|
|
|
collision_count_[num_collisions] += 1;
|
2012-07-24 00:01:50 +00:00
|
|
|
}
|
|
|
|
return index; // Index of symbol if found or slot into which to add symbol.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template intptr_t Symbols::FindIndex(const Array& symbol_table,
|
|
|
|
const uint8_t* characters,
|
|
|
|
intptr_t len,
|
|
|
|
intptr_t hash);
|
|
|
|
template intptr_t Symbols::FindIndex(const Array& symbol_table,
|
|
|
|
const uint16_t* characters,
|
|
|
|
intptr_t len,
|
|
|
|
intptr_t hash);
|
2012-11-20 15:23:41 +00:00
|
|
|
template intptr_t Symbols::FindIndex(const Array& symbol_table,
|
2012-11-21 00:30:27 +00:00
|
|
|
const int32_t* characters,
|
2012-11-20 15:23:41 +00:00
|
|
|
intptr_t len,
|
|
|
|
intptr_t hash);
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
|
|
|
|
intptr_t Symbols::FindIndex(const Array& symbol_table,
|
|
|
|
const String& str,
|
|
|
|
intptr_t begin_index,
|
|
|
|
intptr_t len,
|
|
|
|
intptr_t hash) {
|
|
|
|
// Last element of the array is the number of used elements.
|
|
|
|
intptr_t table_size = symbol_table.Length() - 1;
|
|
|
|
intptr_t index = hash % table_size;
|
2012-12-12 00:35:48 +00:00
|
|
|
intptr_t num_collisions = 0;
|
2012-07-24 00:01:50 +00:00
|
|
|
|
|
|
|
String& symbol = String::Handle();
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-07-24 00:01:50 +00:00
|
|
|
while (!symbol.IsNull() && !symbol.Equals(str, begin_index, len)) {
|
|
|
|
index = (index + 1) % table_size; // Move to next element.
|
2013-01-23 20:01:31 +00:00
|
|
|
symbol ^= symbol_table.At(index);
|
2012-12-12 00:35:48 +00:00
|
|
|
num_collisions += 1;
|
|
|
|
}
|
|
|
|
if (FLAG_dump_symbol_stats) {
|
|
|
|
if (num_collisions >= kMaxCollisionBuckets) {
|
|
|
|
num_collisions = (kMaxCollisionBuckets - 1);
|
|
|
|
}
|
|
|
|
collision_count_[num_collisions] += 1;
|
2012-07-24 00:01:50 +00:00
|
|
|
}
|
|
|
|
return index; // Index of symbol if found or slot into which to add symbol.
|
|
|
|
}
|
|
|
|
|
2012-08-06 21:56:39 +00:00
|
|
|
|
|
|
|
intptr_t Symbols::LookupVMSymbol(RawObject* obj) {
|
2013-01-02 19:31:59 +00:00
|
|
|
for (intptr_t i = 1; i < Symbols::kMaxPredefinedId; i++) {
|
|
|
|
if (symbol_handles_[i]->raw() == obj) {
|
2012-08-08 19:46:23 +00:00
|
|
|
return (i + kMaxPredefinedObjectIds);
|
2012-08-06 21:56:39 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-08 19:46:23 +00:00
|
|
|
return kInvalidIndex;
|
2012-08-06 21:56:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawObject* Symbols::GetVMSymbol(intptr_t object_id) {
|
|
|
|
ASSERT(IsVMSymbolId(object_id));
|
2012-08-08 19:46:23 +00:00
|
|
|
intptr_t i = (object_id - kMaxPredefinedObjectIds);
|
2013-01-02 19:31:59 +00:00
|
|
|
if ((i > kIllegal) && (i < Symbols::kMaxPredefinedId)) {
|
|
|
|
return symbol_handles_[i]->raw();
|
|
|
|
}
|
|
|
|
return Object::null();
|
2012-08-06 21:56:39 +00:00
|
|
|
}
|
|
|
|
|
2012-07-24 00:01:50 +00:00
|
|
|
} // namespace dart
|