Commit 5cbb2094 authored by bak@chromium.org's avatar bak@chromium.org

Removed virtual behavior from Dictionaries.

Review URL: http://codereview.chromium.org/150168

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2324 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9518261f
...@@ -1434,8 +1434,8 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from, ...@@ -1434,8 +1434,8 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
} }
} }
} else { } else {
Handle<Dictionary> properties = Handle<StringDictionary> properties =
Handle<Dictionary>(from->property_dictionary()); Handle<StringDictionary>(from->property_dictionary());
int capacity = properties->Capacity(); int capacity = properties->Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* raw_key(properties->KeyAt(i)); Object* raw_key(properties->KeyAt(i));
......
...@@ -37,8 +37,8 @@ namespace internal { ...@@ -37,8 +37,8 @@ namespace internal {
Handle<Code> CodeStub::GetCode() { Handle<Code> CodeStub::GetCode() {
uint32_t key = GetKey(); uint32_t key = GetKey();
int index = Heap::code_stubs()->FindNumberEntry(key); int index = Heap::code_stubs()->FindEntry(key);
if (index == -1) { if (index == NumberDictionary::kNotFound) {
HandleScope scope; HandleScope scope;
// Update the static counter each time a new code stub is generated. // Update the static counter each time a new code stub is generated.
...@@ -80,14 +80,15 @@ Handle<Code> CodeStub::GetCode() { ...@@ -80,14 +80,15 @@ Handle<Code> CodeStub::GetCode() {
#endif #endif
// Update the dictionary and the root in Heap. // Update the dictionary and the root in Heap.
Handle<Dictionary> dict = Handle<NumberDictionary> dict =
Factory::DictionaryAtNumberPut(Handle<Dictionary>(Heap::code_stubs()), Factory::DictionaryAtNumberPut(
Handle<NumberDictionary>(Heap::code_stubs()),
key, key,
code); code);
Heap::set_code_stubs(*dict); Heap::set_code_stubs(*dict);
index = Heap::code_stubs()->FindNumberEntry(key); index = Heap::code_stubs()->FindEntry(key);
} }
ASSERT(index != -1); ASSERT(index != NumberDictionary::kNotFound);
return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index))); return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index)));
} }
......
...@@ -49,9 +49,17 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size) { ...@@ -49,9 +49,17 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size) {
} }
Handle<Dictionary> Factory::NewDictionary(int at_least_space_for) { Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) {
ASSERT(0 <= at_least_space_for); ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(Dictionary::Allocate(at_least_space_for), Dictionary); CALL_HEAP_FUNCTION(StringDictionary::Allocate(at_least_space_for),
StringDictionary);
}
Handle<NumberDictionary> Factory::NewNumberDictionary(int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(NumberDictionary::Allocate(at_least_space_for),
NumberDictionary);
} }
...@@ -655,10 +663,11 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) { ...@@ -655,10 +663,11 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
} }
Handle<Dictionary> Factory::DictionaryAtNumberPut(Handle<Dictionary> dictionary, Handle<NumberDictionary> Factory::DictionaryAtNumberPut(
Handle<NumberDictionary> dictionary,
uint32_t key, uint32_t key,
Handle<Object> value) { Handle<Object> value) {
CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), Dictionary); CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), NumberDictionary);
} }
......
...@@ -47,7 +47,9 @@ class Factory : public AllStatic { ...@@ -47,7 +47,9 @@ class Factory : public AllStatic {
// Allocate a new fixed array with non-existing entries (the hole). // Allocate a new fixed array with non-existing entries (the hole).
static Handle<FixedArray> NewFixedArrayWithHoles(int size); static Handle<FixedArray> NewFixedArrayWithHoles(int size);
static Handle<Dictionary> NewDictionary(int at_least_space_for); static Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for);
static Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
static Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors); static Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
...@@ -313,7 +315,8 @@ class Factory : public AllStatic { ...@@ -313,7 +315,8 @@ class Factory : public AllStatic {
static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name); static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>, static Handle<NumberDictionary> DictionaryAtNumberPut(
Handle<NumberDictionary>,
uint32_t key, uint32_t key,
Handle<Object> value); Handle<Object> value);
......
...@@ -198,7 +198,8 @@ class FixedArray; ...@@ -198,7 +198,8 @@ class FixedArray;
class FunctionEntry; class FunctionEntry;
class FunctionLiteral; class FunctionLiteral;
class FunctionTemplateInfo; class FunctionTemplateInfo;
class Dictionary; class NumberDictionary;
class StringDictionary;
class FreeStoreAllocationPolicy; class FreeStoreAllocationPolicy;
template <typename T> class Handle; template <typename T> class Handle;
class Heap; class Heap;
......
...@@ -1392,14 +1392,14 @@ bool Heap::CreateInitialObjects() { ...@@ -1392,14 +1392,14 @@ bool Heap::CreateInitialObjects() {
prototype_accessors_ = Proxy::cast(obj); prototype_accessors_ = Proxy::cast(obj);
// Allocate the code_stubs dictionary. // Allocate the code_stubs dictionary.
obj = Dictionary::Allocate(4); obj = NumberDictionary::Allocate(4);
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
code_stubs_ = Dictionary::cast(obj); code_stubs_ = NumberDictionary::cast(obj);
// Allocate the non_monomorphic_cache used in stub-cache.cc // Allocate the non_monomorphic_cache used in stub-cache.cc
obj = Dictionary::Allocate(4); obj = NumberDictionary::Allocate(4);
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
non_monomorphic_cache_ = Dictionary::cast(obj); non_monomorphic_cache_ = NumberDictionary::cast(obj);
CreateFixedStubs(); CreateFixedStubs();
...@@ -2563,7 +2563,7 @@ Object* Heap::AllocateHashTable(int length) { ...@@ -2563,7 +2563,7 @@ Object* Heap::AllocateHashTable(int length) {
Object* result = Heap::AllocateFixedArray(length); Object* result = Heap::AllocateFixedArray(length);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
reinterpret_cast<Array*>(result)->set_map(hash_table_map()); reinterpret_cast<Array*>(result)->set_map(hash_table_map());
ASSERT(result->IsDictionary()); ASSERT(result->IsHashTable());
return result; return result;
} }
......
...@@ -118,8 +118,8 @@ namespace internal { ...@@ -118,8 +118,8 @@ namespace internal {
V(Map, neander_map) \ V(Map, neander_map) \
V(JSObject, message_listeners) \ V(JSObject, message_listeners) \
V(Proxy, prototype_accessors) \ V(Proxy, prototype_accessors) \
V(Dictionary, code_stubs) \ V(NumberDictionary, code_stubs) \
V(Dictionary, non_monomorphic_cache) \ V(NumberDictionary, non_monomorphic_cache) \
V(Code, js_entry_code) \ V(Code, js_entry_code) \
V(Code, js_construct_entry_code) \ V(Code, js_construct_entry_code) \
V(Code, c_entry_code) \ V(Code, c_entry_code) \
...@@ -692,10 +692,10 @@ class Heap : public AllStatic { ...@@ -692,10 +692,10 @@ class Heap : public AllStatic {
static inline AllocationSpace TargetSpaceId(InstanceType type); static inline AllocationSpace TargetSpaceId(InstanceType type);
// Sets the stub_cache_ (only used when expanding the dictionary). // Sets the stub_cache_ (only used when expanding the dictionary).
static void set_code_stubs(Dictionary* value) { code_stubs_ = value; } static void set_code_stubs(NumberDictionary* value) { code_stubs_ = value; }
// Sets the non_monomorphic_cache_ (only used when expanding the dictionary). // Sets the non_monomorphic_cache_ (only used when expanding the dictionary).
static void set_non_monomorphic_cache(Dictionary* value) { static void set_non_monomorphic_cache(NumberDictionary* value) {
non_monomorphic_cache_ = value; non_monomorphic_cache_ = value;
} }
......
...@@ -83,7 +83,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, ...@@ -83,7 +83,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
// Compute the capacity mask. // Compute the capacity mask.
const int kCapacityOffset = const int kCapacityOffset =
Array::kHeaderSize + Dictionary::kCapacityIndex * kPointerSize; Array::kHeaderSize + StringDictionary::kCapacityIndex * kPointerSize;
__ mov(r2, FieldOperand(r0, kCapacityOffset)); __ mov(r2, FieldOperand(r0, kCapacityOffset));
__ shr(r2, kSmiTagSize); // convert smi to int __ shr(r2, kSmiTagSize); // convert smi to int
__ dec(r2); __ dec(r2);
...@@ -93,18 +93,18 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, ...@@ -93,18 +93,18 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
// cover ~93% of loads from dictionaries. // cover ~93% of loads from dictionaries.
static const int kProbes = 4; static const int kProbes = 4;
const int kElementsStartOffset = const int kElementsStartOffset =
Array::kHeaderSize + Dictionary::kElementsStartIndex * kPointerSize; Array::kHeaderSize + StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) { for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
__ mov(r1, FieldOperand(name, String::kLengthOffset)); __ mov(r1, FieldOperand(name, String::kLengthOffset));
__ shr(r1, String::kHashShift); __ shr(r1, String::kHashShift);
if (i > 0) { if (i > 0) {
__ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i))); __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
} }
__ and_(r1, Operand(r2)); __ and_(r1, Operand(r2));
// Scale the index by multiplying by the element size. // Scale the index by multiplying by the entry size.
ASSERT(Dictionary::kElementSize == 3); ASSERT(StringDictionary::kEntrySize == 3);
__ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
// Check if the key is identical to the name. // Check if the key is identical to the name.
......
...@@ -744,12 +744,12 @@ void Proxy::ProxyVerify() { ...@@ -744,12 +744,12 @@ void Proxy::ProxyVerify() {
ASSERT(IsProxy()); ASSERT(IsProxy());
} }
template<typename Shape, typename Key>
void Dictionary::Print() { void Dictionary<Shape, Key>::Print() {
int capacity = Capacity(); int capacity = HashTable<Shape, Key>::Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i); Object* k = HashTable<Shape, Key>::KeyAt(i);
if (IsKey(k)) { if (HashTable<Shape, Key>::IsKey(k)) {
PrintF(" "); PrintF(" ");
if (k->IsString()) { if (k->IsString()) {
String::cast(k)->StringPrint(); String::cast(k)->StringPrint();
...@@ -1017,7 +1017,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) { ...@@ -1017,7 +1017,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
info->number_of_fast_used_fields_ += map()->NextFreePropertyIndex(); info->number_of_fast_used_fields_ += map()->NextFreePropertyIndex();
info->number_of_fast_unused_fields_ += map()->unused_property_fields(); info->number_of_fast_unused_fields_ += map()->unused_property_fields();
} else { } else {
Dictionary* dict = property_dictionary(); StringDictionary* dict = property_dictionary();
info->number_of_slow_used_properties_ += dict->NumberOfElements(); info->number_of_slow_used_properties_ += dict->NumberOfElements();
info->number_of_slow_unused_properties_ += info->number_of_slow_unused_properties_ +=
dict->Capacity() - dict->NumberOfElements(); dict->Capacity() - dict->NumberOfElements();
...@@ -1034,7 +1034,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) { ...@@ -1034,7 +1034,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
info->number_of_fast_used_elements_ += len - holes; info->number_of_fast_used_elements_ += len - holes;
info->number_of_fast_unused_elements_ += holes; info->number_of_fast_unused_elements_ += holes;
} else { } else {
Dictionary* dict = element_dictionary(); NumberDictionary* dict = element_dictionary();
info->number_of_slow_used_elements_ += dict->NumberOfElements(); info->number_of_slow_used_elements_ += dict->NumberOfElements();
info->number_of_slow_unused_elements_ += info->number_of_slow_unused_elements_ +=
dict->Capacity() - dict->NumberOfElements(); dict->Capacity() - dict->NumberOfElements();
......
...@@ -1370,15 +1370,14 @@ void DescriptorArray::Swap(int first, int second) { ...@@ -1370,15 +1370,14 @@ void DescriptorArray::Swap(int first, int second) {
} }
bool Dictionary::requires_slow_elements() { bool NumberDictionary::requires_slow_elements() {
Object* max_index_object = get(kMaxNumberKeyIndex); Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi()) return false; if (!max_index_object->IsSmi()) return false;
return 0 != return 0 !=
(Smi::cast(max_index_object)->value() & kRequiresSlowElementsMask); (Smi::cast(max_index_object)->value() & kRequiresSlowElementsMask);
} }
uint32_t NumberDictionary::max_number_key() {
uint32_t Dictionary::max_number_key() {
ASSERT(!requires_slow_elements()); ASSERT(!requires_slow_elements());
Object* max_index_object = get(kMaxNumberKeyIndex); Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi()) return 0; if (!max_index_object->IsSmi()) return 0;
...@@ -1386,8 +1385,7 @@ uint32_t Dictionary::max_number_key() { ...@@ -1386,8 +1385,7 @@ uint32_t Dictionary::max_number_key() {
return value >> kRequiresSlowElementsTagSize; return value >> kRequiresSlowElementsTagSize;
} }
void NumberDictionary::set_requires_slow_elements() {
void Dictionary::set_requires_slow_elements() {
set(kMaxNumberKeyIndex, set(kMaxNumberKeyIndex,
Smi::FromInt(kRequiresSlowElementsMask), Smi::FromInt(kRequiresSlowElementsMask),
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
...@@ -1400,7 +1398,6 @@ void Dictionary::set_requires_slow_elements() { ...@@ -1400,7 +1398,6 @@ void Dictionary::set_requires_slow_elements() {
CAST_ACCESSOR(FixedArray) CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(DescriptorArray) CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(Dictionary)
CAST_ACCESSOR(SymbolTable) CAST_ACCESSOR(SymbolTable)
CAST_ACCESSOR(CompilationCacheTable) CAST_ACCESSOR(CompilationCacheTable)
CAST_ACCESSOR(MapCache) CAST_ACCESSOR(MapCache)
...@@ -1439,9 +1436,9 @@ CAST_ACCESSOR(Struct) ...@@ -1439,9 +1436,9 @@ CAST_ACCESSOR(Struct)
STRUCT_LIST(MAKE_STRUCT_CAST) STRUCT_LIST(MAKE_STRUCT_CAST)
#undef MAKE_STRUCT_CAST #undef MAKE_STRUCT_CAST
template <int prefix_size, int elem_size>
HashTable<prefix_size, elem_size>* HashTable<prefix_size, elem_size>::cast( template <typename Shape, typename Key>
Object* obj) { HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
ASSERT(obj->IsHashTable()); ASSERT(obj->IsHashTable());
return reinterpret_cast<HashTable*>(obj); return reinterpret_cast<HashTable*>(obj);
} }
...@@ -2468,15 +2465,15 @@ bool JSObject::HasIndexedInterceptor() { ...@@ -2468,15 +2465,15 @@ bool JSObject::HasIndexedInterceptor() {
} }
Dictionary* JSObject::property_dictionary() { StringDictionary* JSObject::property_dictionary() {
ASSERT(!HasFastProperties()); ASSERT(!HasFastProperties());
return Dictionary::cast(properties()); return StringDictionary::cast(properties());
} }
Dictionary* JSObject::element_dictionary() { NumberDictionary* JSObject::element_dictionary() {
ASSERT(!HasFastElements()); ASSERT(!HasFastElements());
return Dictionary::cast(elements()); return NumberDictionary::cast(elements());
} }
...@@ -2640,16 +2637,17 @@ void AccessorInfo::set_property_attributes(PropertyAttributes attributes) { ...@@ -2640,16 +2637,17 @@ void AccessorInfo::set_property_attributes(PropertyAttributes attributes) {
set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes))); set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes)));
} }
void Dictionary::SetEntry(int entry, template<typename Shape, typename Key>
void Dictionary<Shape, Key>::SetEntry(int entry,
Object* key, Object* key,
Object* value, Object* value,
PropertyDetails details) { PropertyDetails details) {
ASSERT(!key->IsString() || details.index() > 0); ASSERT(!key->IsString() || details.index() > 0);
int index = EntryToIndex(entry); int index = HashTable<Shape, Key>::EntryToIndex(entry);
WriteBarrierMode mode = GetWriteBarrierMode(); WriteBarrierMode mode = FixedArray::GetWriteBarrierMode();
set(index, key, mode); FixedArray::set(index, key, mode);
set(index+1, value, mode); FixedArray::set(index+1, value, mode);
fast_set(this, index+2, details.AsSmi()); FixedArray::fast_set(this, index+2, details.AsSmi());
} }
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "disassembler.h" #include "disassembler.h"
#endif #endif
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -428,17 +429,17 @@ Object* JSObject::SetNormalizedProperty(String* name, ...@@ -428,17 +429,17 @@ Object* JSObject::SetNormalizedProperty(String* name,
Object* value, Object* value,
PropertyDetails details) { PropertyDetails details) {
ASSERT(!HasFastProperties()); ASSERT(!HasFastProperties());
int entry = property_dictionary()->FindStringEntry(name); int entry = property_dictionary()->FindEntry(name);
if (entry == Dictionary::kNotFound) { if (entry == StringDictionary::kNotFound) {
Object* store_value = value; Object* store_value = value;
if (IsGlobalObject()) { if (IsGlobalObject()) {
store_value = Heap::AllocateJSGlobalPropertyCell(value); store_value = Heap::AllocateJSGlobalPropertyCell(value);
if (store_value->IsFailure()) return store_value; if (store_value->IsFailure()) return store_value;
} }
Object* dict = Object* dict =
property_dictionary()->AddStringEntry(name, store_value, details); property_dictionary()->Add(name, store_value, details);
if (dict->IsFailure()) return dict; if (dict->IsFailure()) return dict;
set_properties(Dictionary::cast(dict)); set_properties(StringDictionary::cast(dict));
return value; return value;
} }
// Preserve enumeration index. // Preserve enumeration index.
...@@ -452,7 +453,7 @@ Object* JSObject::SetNormalizedProperty(String* name, ...@@ -452,7 +453,7 @@ Object* JSObject::SetNormalizedProperty(String* name,
// Please note we have to update the property details. // Please note we have to update the property details.
property_dictionary()->DetailsAtPut(entry, details); property_dictionary()->DetailsAtPut(entry, details);
} else { } else {
property_dictionary()->SetStringEntry(entry, name, value, details); property_dictionary()->SetEntry(entry, name, value, details);
} }
return value; return value;
} }
...@@ -460,9 +461,9 @@ Object* JSObject::SetNormalizedProperty(String* name, ...@@ -460,9 +461,9 @@ Object* JSObject::SetNormalizedProperty(String* name,
Object* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) { Object* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
ASSERT(!HasFastProperties()); ASSERT(!HasFastProperties());
Dictionary* dictionary = property_dictionary(); StringDictionary* dictionary = property_dictionary();
int entry = dictionary->FindStringEntry(name); int entry = dictionary->FindEntry(name);
if (entry != Dictionary::kNotFound) { if (entry != StringDictionary::kNotFound) {
// If we have a global object set the cell to the hole. // If we have a global object set the cell to the hole.
if (IsGlobalObject()) { if (IsGlobalObject()) {
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
...@@ -1340,16 +1341,16 @@ Object* JSObject::AddSlowProperty(String* name, ...@@ -1340,16 +1341,16 @@ Object* JSObject::AddSlowProperty(String* name,
Object* value, Object* value,
PropertyAttributes attributes) { PropertyAttributes attributes) {
ASSERT(!HasFastProperties()); ASSERT(!HasFastProperties());
Dictionary* dict = property_dictionary(); StringDictionary* dict = property_dictionary();
Object* store_value = value; Object* store_value = value;
if (IsGlobalObject()) { if (IsGlobalObject()) {
// In case name is an orphaned property reuse the cell. // In case name is an orphaned property reuse the cell.
int entry = dict->FindStringEntry(name); int entry = dict->FindEntry(name);
if (entry != Dictionary::kNotFound) { if (entry != StringDictionary::kNotFound) {
store_value = dict->ValueAt(entry); store_value = dict->ValueAt(entry);
JSGlobalPropertyCell::cast(store_value)->set_value(value); JSGlobalPropertyCell::cast(store_value)->set_value(value);
PropertyDetails details = PropertyDetails(attributes, NORMAL); PropertyDetails details = PropertyDetails(attributes, NORMAL);
dict->SetStringEntry(entry, name, store_value, details); dict->SetEntry(entry, name, store_value, details);
return value; return value;
} }
store_value = Heap::AllocateJSGlobalPropertyCell(value); store_value = Heap::AllocateJSGlobalPropertyCell(value);
...@@ -1357,9 +1358,9 @@ Object* JSObject::AddSlowProperty(String* name, ...@@ -1357,9 +1358,9 @@ Object* JSObject::AddSlowProperty(String* name,
JSGlobalPropertyCell::cast(store_value)->set_value(value); JSGlobalPropertyCell::cast(store_value)->set_value(value);
} }
PropertyDetails details = PropertyDetails(attributes, NORMAL); PropertyDetails details = PropertyDetails(attributes, NORMAL);
Object* result = dict->AddStringEntry(name, store_value, details); Object* result = dict->Add(name, store_value, details);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
if (dict != result) set_properties(Dictionary::cast(result)); if (dict != result) set_properties(StringDictionary::cast(result));
return value; return value;
} }
...@@ -1405,8 +1406,8 @@ Object* JSObject::SetPropertyPostInterceptor(String* name, ...@@ -1405,8 +1406,8 @@ Object* JSObject::SetPropertyPostInterceptor(String* name,
Object* JSObject::ReplaceSlowProperty(String* name, Object* JSObject::ReplaceSlowProperty(String* name,
Object* value, Object* value,
PropertyAttributes attributes) { PropertyAttributes attributes) {
Dictionary* dictionary = property_dictionary(); StringDictionary* dictionary = property_dictionary();
int old_index = dictionary->FindStringEntry(name); int old_index = dictionary->FindEntry(name);
int new_enumeration_index = 0; // 0 means "Use the next available index." int new_enumeration_index = 0; // 0 means "Use the next available index."
if (old_index != -1) { if (old_index != -1) {
// All calls to ReplaceSlowProperty have had all transitions removed. // All calls to ReplaceSlowProperty have had all transitions removed.
...@@ -1646,9 +1647,9 @@ Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { ...@@ -1646,9 +1647,9 @@ Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) {
pt != Heap::null_value(); pt != Heap::null_value();
pt = pt->GetPrototype()) { pt = pt->GetPrototype()) {
if (JSObject::cast(pt)->HasFastElements()) continue; if (JSObject::cast(pt)->HasFastElements()) continue;
Dictionary* dictionary = JSObject::cast(pt)->element_dictionary(); NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != StringDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry); Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
...@@ -1698,8 +1699,8 @@ void JSObject::LocalLookupRealNamedProperty(String* name, ...@@ -1698,8 +1699,8 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
return; return;
} }
} else { } else {
int entry = property_dictionary()->FindStringEntry(name); int entry = property_dictionary()->FindEntry(name);
if (entry != Dictionary::kNotFound) { if (entry != StringDictionary::kNotFound) {
// Make sure to disallow caching for uninitialized constants // Make sure to disallow caching for uninitialized constants
// found in the dictionary-mode objects. // found in the dictionary-mode objects.
Object* value = property_dictionary()->ValueAt(entry); Object* value = property_dictionary()->ValueAt(entry);
...@@ -2101,9 +2102,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { ...@@ -2101,9 +2102,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
// Allocate new content // Allocate new content
Object* obj = Object* obj =
Dictionary::Allocate(map()->NumberOfDescribedProperties() * 2 + 4); StringDictionary::Allocate(map()->NumberOfDescribedProperties() * 2 + 4);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
Dictionary* dictionary = Dictionary::cast(obj); StringDictionary* dictionary = StringDictionary::cast(obj);
for (DescriptorReader r(map()->instance_descriptors()); for (DescriptorReader r(map()->instance_descriptors());
!r.eos(); !r.eos();
...@@ -2118,9 +2119,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { ...@@ -2118,9 +2119,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
value = Heap::AllocateJSGlobalPropertyCell(value); value = Heap::AllocateJSGlobalPropertyCell(value);
if (value->IsFailure()) return value; if (value->IsFailure()) return value;
} }
Object* result = dictionary->AddStringEntry(r.GetKey(), value, d); Object* result = dictionary->Add(r.GetKey(), value, d);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result); dictionary = StringDictionary::cast(result);
break; break;
} }
case FIELD: { case FIELD: {
...@@ -2131,9 +2132,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { ...@@ -2131,9 +2132,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
value = Heap::AllocateJSGlobalPropertyCell(value); value = Heap::AllocateJSGlobalPropertyCell(value);
if (value->IsFailure()) return value; if (value->IsFailure()) return value;
} }
Object* result = dictionary->AddStringEntry(r.GetKey(), value, d); Object* result = dictionary->Add(r.GetKey(), value, d);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result); dictionary = StringDictionary::cast(result);
break; break;
} }
case CALLBACKS: { case CALLBACKS: {
...@@ -2144,9 +2145,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { ...@@ -2144,9 +2145,9 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
value = Heap::AllocateJSGlobalPropertyCell(value); value = Heap::AllocateJSGlobalPropertyCell(value);
if (value->IsFailure()) return value; if (value->IsFailure()) return value;
} }
Object* result = dictionary->AddStringEntry(r.GetKey(), value, d); Object* result = dictionary->Add(r.GetKey(), value, d);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result); dictionary = StringDictionary::cast(result);
break; break;
} }
case MAP_TRANSITION: case MAP_TRANSITION:
...@@ -2219,9 +2220,9 @@ Object* JSObject::NormalizeElements() { ...@@ -2219,9 +2220,9 @@ Object* JSObject::NormalizeElements() {
int length = IsJSArray() ? int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() : Smi::cast(JSArray::cast(this)->length())->value() :
array->length(); array->length();
Object* obj = Dictionary::Allocate(length); Object* obj = NumberDictionary::Allocate(length);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
Dictionary* dictionary = Dictionary::cast(obj); NumberDictionary* dictionary = NumberDictionary::cast(obj);
// Copy entries. // Copy entries.
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Object* value = array->get(i); Object* value = array->get(i);
...@@ -2229,7 +2230,7 @@ Object* JSObject::NormalizeElements() { ...@@ -2229,7 +2230,7 @@ Object* JSObject::NormalizeElements() {
PropertyDetails details = PropertyDetails(NONE, NORMAL); PropertyDetails details = PropertyDetails(NONE, NORMAL);
Object* result = dictionary->AddNumberEntry(i, array->get(i), details); Object* result = dictionary->AddNumberEntry(i, array->get(i), details);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result); dictionary = NumberDictionary::cast(result);
} }
} }
// Switch to using the dictionary as the backing storage for elements. // Switch to using the dictionary as the backing storage for elements.
...@@ -2306,9 +2307,9 @@ Object* JSObject::DeleteElementPostInterceptor(uint32_t index, ...@@ -2306,9 +2307,9 @@ Object* JSObject::DeleteElementPostInterceptor(uint32_t index,
return Heap::true_value(); return Heap::true_value();
} }
ASSERT(!HasFastElements()); ASSERT(!HasFastElements());
Dictionary* dictionary = element_dictionary(); NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
return dictionary->DeleteProperty(entry, mode); return dictionary->DeleteProperty(entry, mode);
} }
return Heap::true_value(); return Heap::true_value();
...@@ -2380,9 +2381,9 @@ Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { ...@@ -2380,9 +2381,9 @@ Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
} }
return Heap::true_value(); return Heap::true_value();
} else { } else {
Dictionary* dictionary = element_dictionary(); NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
return dictionary->DeleteProperty(entry, mode); return dictionary->DeleteProperty(entry, mode);
} }
} }
...@@ -2687,9 +2688,9 @@ Object* JSObject::DefineGetterSetter(String* name, ...@@ -2687,9 +2688,9 @@ Object* JSObject::DefineGetterSetter(String* name,
if (is_element) { if (is_element) {
// Lookup the index. // Lookup the index.
if (!HasFastElements()) { if (!HasFastElements()) {
Dictionary* dictionary = element_dictionary(); NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry); Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.IsReadOnly()) return Heap::undefined_value(); if (details.IsReadOnly()) return Heap::undefined_value();
...@@ -2725,14 +2726,14 @@ Object* JSObject::DefineGetterSetter(String* name, ...@@ -2725,14 +2726,14 @@ Object* JSObject::DefineGetterSetter(String* name,
// Update the dictionary with the new CALLBACKS property. // Update the dictionary with the new CALLBACKS property.
Object* dict = Object* dict =
element_dictionary()->SetOrAddNumberEntry(index, structure, details); element_dictionary()->Set(index, structure, details);
if (dict->IsFailure()) return dict; if (dict->IsFailure()) return dict;
// If name is an index we need to stay in slow case. // If name is an index we need to stay in slow case.
Dictionary* elements = Dictionary::cast(dict); NumberDictionary* elements = NumberDictionary::cast(dict);
elements->set_requires_slow_elements(); elements->set_requires_slow_elements();
// Set the potential new dictionary on the object. // Set the potential new dictionary on the object.
set_elements(Dictionary::cast(dict)); set_elements(NumberDictionary::cast(dict));
} else { } else {
// Normalize object to make this operation simple. // Normalize object to make this operation simple.
Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
...@@ -2799,9 +2800,9 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) { ...@@ -2799,9 +2800,9 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
obj = JSObject::cast(obj)->GetPrototype()) { obj = JSObject::cast(obj)->GetPrototype()) {
JSObject* jsObject = JSObject::cast(obj); JSObject* jsObject = JSObject::cast(obj);
if (!jsObject->HasFastElements()) { if (!jsObject->HasFastElements()) {
Dictionary* dictionary = jsObject->element_dictionary(); NumberDictionary* dictionary = jsObject->element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry); Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
...@@ -3004,7 +3005,7 @@ Object* FixedArray::AddKeysFromJSArray(JSArray* array) { ...@@ -3004,7 +3005,7 @@ Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
return UnionOfKeys(array->elements()); return UnionOfKeys(array->elements());
} }
ASSERT(!array->HasFastElements()); ASSERT(!array->HasFastElements());
Dictionary* dict = array->element_dictionary(); NumberDictionary* dict = array->element_dictionary();
int size = dict->NumberOfElements(); int size = dict->NumberOfElements();
// Allocate a temporary fixed array. // Allocate a temporary fixed array.
...@@ -5075,7 +5076,7 @@ void JSObject::SetFastElements(FixedArray* elems) { ...@@ -5075,7 +5076,7 @@ void JSObject::SetFastElements(FixedArray* elems) {
elems->set(i, old_elements->get(i), mode); elems->set(i, old_elements->get(i), mode);
} }
} else { } else {
Dictionary* dictionary = Dictionary::cast(elements()); NumberDictionary* dictionary = NumberDictionary::cast(elements());
for (int i = 0; i < dictionary->Capacity(); i++) { for (int i = 0; i < dictionary->Capacity(); i++) {
Object* key = dictionary->KeyAt(i); Object* key = dictionary->KeyAt(i);
if (key->IsNumber()) { if (key->IsNumber()) {
...@@ -5240,7 +5241,8 @@ bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { ...@@ -5240,7 +5241,8 @@ bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
return true; return true;
} }
} else { } else {
if (element_dictionary()->FindNumberEntry(index) != Dictionary::kNotFound) { if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
return true; return true;
} }
} }
...@@ -5317,8 +5319,8 @@ bool JSObject::HasLocalElement(uint32_t index) { ...@@ -5317,8 +5319,8 @@ bool JSObject::HasLocalElement(uint32_t index) {
return (index < length) && return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole(); !FixedArray::cast(elements())->get(index)->IsTheHole();
} else { } else {
return element_dictionary()->FindNumberEntry(index) return element_dictionary()->FindEntry(index)
!= Dictionary::kNotFound; != NumberDictionary::kNotFound;
} }
} }
...@@ -5344,7 +5346,8 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { ...@@ -5344,7 +5346,8 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
if ((index < length) && if ((index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole()) return true; !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
} else { } else {
if (element_dictionary()->FindNumberEntry(index) != Dictionary::kNotFound) { if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
return true; return true;
} }
} }
...@@ -5479,10 +5482,10 @@ Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { ...@@ -5479,10 +5482,10 @@ Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) {
// Insert element in the dictionary. // Insert element in the dictionary.
FixedArray* elms = FixedArray::cast(elements()); FixedArray* elms = FixedArray::cast(elements());
Dictionary* dictionary = Dictionary::cast(elms); NumberDictionary* dictionary = NumberDictionary::cast(elms);
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry); Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
...@@ -5531,7 +5534,7 @@ Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { ...@@ -5531,7 +5534,7 @@ Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) {
CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length)); CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length));
JSArray::cast(this)->set_length(Smi::FromInt(new_length)); JSArray::cast(this)->set_length(Smi::FromInt(new_length));
} else { } else {
new_length = Dictionary::cast(elements())->max_number_key() + 1; new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
} }
Object* obj = Heap::AllocateFixedArrayWithHoles(new_length); Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
...@@ -5574,9 +5577,9 @@ Object* JSObject::GetElementPostInterceptor(JSObject* receiver, ...@@ -5574,9 +5577,9 @@ Object* JSObject::GetElementPostInterceptor(JSObject* receiver,
if (!value->IsTheHole()) return value; if (!value->IsTheHole()) return value;
} }
} else { } else {
Dictionary* dictionary = element_dictionary(); NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry); Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
...@@ -5658,9 +5661,9 @@ Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) { ...@@ -5658,9 +5661,9 @@ Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) {
if (!value->IsTheHole()) return value; if (!value->IsTheHole()) return value;
} }
} else { } else {
Dictionary* dictionary = element_dictionary(); NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindEntry(index);
if (entry != Dictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry); Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
...@@ -5696,7 +5699,7 @@ bool JSObject::HasDenseElements() { ...@@ -5696,7 +5699,7 @@ bool JSObject::HasDenseElements() {
if (!elms->get(i)->IsTheHole()) number_of_elements++; if (!elms->get(i)->IsTheHole()) number_of_elements++;
} }
} else { } else {
Dictionary* dictionary = Dictionary::cast(elements()); NumberDictionary* dictionary = NumberDictionary::cast(elements());
capacity = dictionary->Capacity(); capacity = dictionary->Capacity();
number_of_elements = dictionary->NumberOfElements(); number_of_elements = dictionary->NumberOfElements();
} }
...@@ -5718,7 +5721,7 @@ bool JSObject::ShouldConvertToSlowElements(int new_capacity) { ...@@ -5718,7 +5721,7 @@ bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
bool JSObject::ShouldConvertToFastElements() { bool JSObject::ShouldConvertToFastElements() {
ASSERT(!HasFastElements()); ASSERT(!HasFastElements());
Dictionary* dictionary = Dictionary::cast(elements()); NumberDictionary* dictionary = NumberDictionary::cast(elements());
// If the elements are sparse, we should not go back to fast case. // If the elements are sparse, we should not go back to fast case.
if (!HasDenseElements()) return false; if (!HasDenseElements()) return false;
// If an element has been added at a very high index in the elements // If an element has been added at a very high index in the elements
...@@ -5737,17 +5740,19 @@ bool JSObject::ShouldConvertToFastElements() { ...@@ -5737,17 +5740,19 @@ bool JSObject::ShouldConvertToFastElements() {
length = dictionary->max_number_key(); length = dictionary->max_number_key();
} }
return static_cast<uint32_t>(dictionary->Capacity()) >= return static_cast<uint32_t>(dictionary->Capacity()) >=
(length / (2 * Dictionary::kElementSize)); (length / (2 * NumberDictionary::kEntrySize));
} }
template<typename Shape, typename Key>
void Dictionary::CopyValuesTo(FixedArray* elements) { void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
int pos = 0; int pos = 0;
int capacity = Capacity(); int capacity = HashTable<Shape, Key>::Capacity();
WriteBarrierMode mode = elements->GetWriteBarrierMode(); WriteBarrierMode mode = elements->GetWriteBarrierMode();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i); Object* k = Dictionary<Shape, Key>::KeyAt(i);
if (IsKey(k)) elements->set(pos++, ValueAt(i), mode); if (Dictionary<Shape, Key>::IsKey(k)) {
elements->set(pos++, ValueAt(i), mode);
}
} }
ASSERT(pos == elements->length()); ASSERT(pos == elements->length());
} }
...@@ -5953,8 +5958,8 @@ bool JSObject::HasRealElementProperty(uint32_t index) { ...@@ -5953,8 +5958,8 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
return (index < length) && return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole(); !FixedArray::cast(elements())->get(index)->IsTheHole();
} }
return element_dictionary()->FindNumberEntry(index) return element_dictionary()->FindEntry(index)
!= Dictionary::kNotFound; != NumberDictionary::kNotFound;
} }
...@@ -6187,38 +6192,49 @@ int JSObject::GetEnumElementKeys(FixedArray* storage) { ...@@ -6187,38 +6192,49 @@ int JSObject::GetEnumElementKeys(FixedArray* storage) {
} }
// The NumberKey uses carries the uint32_t as key. bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
// This avoids allocation in HasProperty. ASSERT(other->IsNumber());
class NumberKey : public HashTableKey { return key == static_cast<uint32_t>(other->Number());
public: }
explicit NumberKey(uint32_t number) : number_(number) { }
bool IsMatch(Object* number) {
return number_ == ToUint32(number);
}
uint32_t Hash() { return ComputeIntegerHash(number_); } uint32_t NumberDictionaryShape::Hash(uint32_t key) {
return ComputeIntegerHash(key);
}
HashFunction GetHashFunction() { return NumberHash; }
Object* GetObject() { uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) {
return Heap::NumberFromDouble(number_); ASSERT(other->IsNumber());
} return ComputeIntegerHash(static_cast<uint32_t>(other->Number()));
}
bool IsStringKey() { return false; }
private: Object* NumberDictionaryShape::AsObject(uint32_t key) {
static uint32_t NumberHash(Object* obj) { return Heap::NumberFromUint32(key);
return ComputeIntegerHash(ToUint32(obj)); }
}
static uint32_t ToUint32(Object* obj) {
ASSERT(obj->IsNumber());
return static_cast<uint32_t>(obj->Number());
}
uint32_t number_; bool StringDictionaryShape::IsMatch(String* key, Object* other) {
}; // We know that all entries in a hash table had their hash keys created.
// Use that knowledge to have fast failure.
if (key->Hash() != String::cast(other)->Hash()) return false;
return key->Equals(String::cast(other));
}
uint32_t StringDictionaryShape::Hash(String* key) {
return key->Hash();
}
uint32_t StringDictionaryShape::HashForObject(String* key, Object* other) {
return String::cast(other)->Hash();
}
Object* StringDictionaryShape::AsObject(String* key) {
return key;
}
// StringKey simply carries a string object as key. // StringKey simply carries a string object as key.
...@@ -6226,12 +6242,12 @@ class StringKey : public HashTableKey { ...@@ -6226,12 +6242,12 @@ class StringKey : public HashTableKey {
public: public:
explicit StringKey(String* string) : explicit StringKey(String* string) :
string_(string), string_(string),
hash_(StringHash(string)) { } hash_(HashForObject(string)) { }
bool IsMatch(Object* string) { bool IsMatch(Object* string) {
// We know that all entries in a hash table had their hash keys created. // We know that all entries in a hash table had their hash keys created.
// Use that knowledge to have fast failure. // Use that knowledge to have fast failure.
if (hash_ != StringHash(string)) { if (hash_ != HashForObject(string)) {
return false; return false;
} }
return string_->Equals(String::cast(string)); return string_->Equals(String::cast(string));
...@@ -6239,15 +6255,9 @@ class StringKey : public HashTableKey { ...@@ -6239,15 +6255,9 @@ class StringKey : public HashTableKey {
uint32_t Hash() { return hash_; } uint32_t Hash() { return hash_; }
HashFunction GetHashFunction() { return StringHash; } uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
Object* GetObject() { return string_; }
static uint32_t StringHash(Object* obj) { Object* AsObject() { return string_; }
return String::cast(obj)->Hash();
}
bool IsStringKey() { return true; }
String* string_; String* string_;
uint32_t hash_; uint32_t hash_;
...@@ -6269,10 +6279,6 @@ class StringSharedKey : public HashTableKey { ...@@ -6269,10 +6279,6 @@ class StringSharedKey : public HashTableKey {
return source->Equals(source_); return source->Equals(source_);
} }
typedef uint32_t (*HashFunction)(Object* obj);
virtual HashFunction GetHashFunction() { return StringSharedHash; }
static uint32_t StringSharedHashHelper(String* source, static uint32_t StringSharedHashHelper(String* source,
SharedFunctionInfo* shared) { SharedFunctionInfo* shared) {
uint32_t hash = source->Hash(); uint32_t hash = source->Hash();
...@@ -6289,18 +6295,18 @@ class StringSharedKey : public HashTableKey { ...@@ -6289,18 +6295,18 @@ class StringSharedKey : public HashTableKey {
return hash; return hash;
} }
static uint32_t StringSharedHash(Object* obj) { uint32_t Hash() {
return StringSharedHashHelper(source_, shared_);
}
uint32_t HashForObject(Object* obj) {
FixedArray* pair = FixedArray::cast(obj); FixedArray* pair = FixedArray::cast(obj);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0)); SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
String* source = String::cast(pair->get(1)); String* source = String::cast(pair->get(1));
return StringSharedHashHelper(source, shared); return StringSharedHashHelper(source, shared);
} }
virtual uint32_t Hash() { Object* AsObject() {
return StringSharedHashHelper(source_, shared_);
}
virtual Object* GetObject() {
Object* obj = Heap::AllocateFixedArray(2); Object* obj = Heap::AllocateFixedArray(2);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
FixedArray* pair = FixedArray::cast(obj); FixedArray* pair = FixedArray::cast(obj);
...@@ -6309,8 +6315,6 @@ class StringSharedKey : public HashTableKey { ...@@ -6309,8 +6315,6 @@ class StringSharedKey : public HashTableKey {
return pair; return pair;
} }
virtual bool IsStringKey() { return false; }
private: private:
String* source_; String* source_;
SharedFunctionInfo* shared_; SharedFunctionInfo* shared_;
...@@ -6332,16 +6336,14 @@ class RegExpKey : public HashTableKey { ...@@ -6332,16 +6336,14 @@ class RegExpKey : public HashTableKey {
uint32_t Hash() { return RegExpHash(string_, flags_); } uint32_t Hash() { return RegExpHash(string_, flags_); }
HashFunction GetHashFunction() { return RegExpObjectHash; } Object* AsObject() {
Object* GetObject() {
// Plain hash maps, which is where regexp keys are used, don't // Plain hash maps, which is where regexp keys are used, don't
// use this function. // use this function.
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
} }
static uint32_t RegExpObjectHash(Object* obj) { uint32_t HashForObject(Object* obj) {
FixedArray* val = FixedArray::cast(obj); FixedArray* val = FixedArray::cast(obj);
return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)), return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
Smi::cast(val->get(JSRegExp::kFlagsIndex))); Smi::cast(val->get(JSRegExp::kFlagsIndex)));
...@@ -6351,8 +6353,6 @@ class RegExpKey : public HashTableKey { ...@@ -6351,8 +6353,6 @@ class RegExpKey : public HashTableKey {
return string->Hash() + flags->value(); return string->Hash() + flags->value();
} }
bool IsStringKey() { return false; }
String* string_; String* string_;
Smi* flags_; Smi* flags_;
}; };
...@@ -6367,10 +6367,6 @@ class Utf8SymbolKey : public HashTableKey { ...@@ -6367,10 +6367,6 @@ class Utf8SymbolKey : public HashTableKey {
return String::cast(string)->IsEqualTo(string_); return String::cast(string)->IsEqualTo(string_);
} }
HashFunction GetHashFunction() {
return StringHash;
}
uint32_t Hash() { uint32_t Hash() {
if (length_field_ != 0) return length_field_ >> String::kHashShift; if (length_field_ != 0) return length_field_ >> String::kHashShift;
unibrow::Utf8InputBuffer<> buffer(string_.start(), unibrow::Utf8InputBuffer<> buffer(string_.start(),
...@@ -6382,17 +6378,15 @@ class Utf8SymbolKey : public HashTableKey { ...@@ -6382,17 +6378,15 @@ class Utf8SymbolKey : public HashTableKey {
return result; return result;
} }
Object* GetObject() { uint32_t HashForObject(Object* other) {
if (length_field_ == 0) Hash(); return String::cast(other)->Hash();
return Heap::AllocateSymbol(string_, chars_, length_field_);
} }
static uint32_t StringHash(Object* obj) { Object* AsObject() {
return String::cast(obj)->Hash(); if (length_field_ == 0) Hash();
return Heap::AllocateSymbol(string_, chars_, length_field_);
} }
bool IsStringKey() { return true; }
Vector<const char> string_; Vector<const char> string_;
uint32_t length_field_; uint32_t length_field_;
int chars_; // Caches the number of characters when computing the hash code. int chars_; // Caches the number of characters when computing the hash code.
...@@ -6404,17 +6398,17 @@ class SymbolKey : public HashTableKey { ...@@ -6404,17 +6398,17 @@ class SymbolKey : public HashTableKey {
public: public:
explicit SymbolKey(String* string) : string_(string) { } explicit SymbolKey(String* string) : string_(string) { }
HashFunction GetHashFunction() {
return StringHash;
}
bool IsMatch(Object* string) { bool IsMatch(Object* string) {
return String::cast(string)->Equals(string_); return String::cast(string)->Equals(string_);
} }
uint32_t Hash() { return string_->Hash(); } uint32_t Hash() { return string_->Hash(); }
Object* GetObject() { uint32_t HashForObject(Object* other) {
return String::cast(other)->Hash();
}
Object* AsObject() {
// If the string is a cons string, attempt to flatten it so that // If the string is a cons string, attempt to flatten it so that
// symbols will most often be flat strings. // symbols will most often be flat strings.
if (StringShape(string_).IsCons()) { if (StringShape(string_).IsCons()) {
...@@ -6442,28 +6436,27 @@ class SymbolKey : public HashTableKey { ...@@ -6442,28 +6436,27 @@ class SymbolKey : public HashTableKey {
return String::cast(obj)->Hash(); return String::cast(obj)->Hash();
} }
bool IsStringKey() { return true; }
String* string_; String* string_;
}; };
template<int prefix_size, int element_size> template<typename Shape, typename Key>
void HashTable<prefix_size, element_size>::IteratePrefix(ObjectVisitor* v) { void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
IteratePointers(v, 0, kElementsStartOffset); IteratePointers(v, 0, kElementsStartOffset);
} }
template<int prefix_size, int element_size> template<typename Shape, typename Key>
void HashTable<prefix_size, element_size>::IterateElements(ObjectVisitor* v) { void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
IteratePointers(v, IteratePointers(v,
kElementsStartOffset, kElementsStartOffset,
kHeaderSize + length() * kPointerSize); kHeaderSize + length() * kPointerSize);
} }
template<int prefix_size, int element_size> template<typename Shape, typename Key>
Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) { Object* HashTable<Shape, Key>::Allocate(
int at_least_space_for) {
int capacity = RoundUpToPowerOf2(at_least_space_for); int capacity = RoundUpToPowerOf2(at_least_space_for);
if (capacity < 4) capacity = 4; // Guarantee min capacity. if (capacity < 4) capacity = 4; // Guarantee min capacity.
Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity)); Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity));
...@@ -6475,27 +6468,28 @@ Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) { ...@@ -6475,27 +6468,28 @@ Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) {
} }
// Find entry for key otherwise return -1. // Find entry for key otherwise return -1.
template <int prefix_size, int element_size> template<typename Shape, typename Key>
int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) { int HashTable<Shape, Key>::FindEntry(Key key) {
uint32_t nof = NumberOfElements(); uint32_t nof = NumberOfElements();
if (nof == 0) return kNotFound; // Bail out if empty. if (nof == 0) return kNotFound; // Bail out if empty.
uint32_t capacity = Capacity(); uint32_t capacity = Capacity();
uint32_t hash = key->Hash(); uint32_t hash = Shape::Hash(key);
uint32_t entry = GetProbe(hash, 0, capacity); uint32_t entry = GetProbe(hash, 0, capacity);
Object* element = KeyAt(entry); Object* element = KeyAt(entry);
uint32_t passed_elements = 0; uint32_t passed_elements = 0;
if (!element->IsNull()) { if (!element->IsNull()) {
if (!element->IsUndefined() && key->IsMatch(element)) return entry; if (!element->IsUndefined() && Shape::IsMatch(key, element)) return entry;
if (++passed_elements == nof) return kNotFound; if (++passed_elements == nof) return kNotFound;
} }
for (uint32_t i = 1; !element->IsUndefined(); i++) { for (uint32_t i = 1; !element->IsUndefined(); i++) {
entry = GetProbe(hash, i, capacity); entry = GetProbe(hash, i, capacity);
element = KeyAt(entry); element = KeyAt(entry);
if (!element->IsNull()) { if (!element->IsNull()) {
if (!element->IsUndefined() && key->IsMatch(element)) return entry; if (!element->IsUndefined() && Shape::IsMatch(key, element)) return entry;
if (++passed_elements == nof) return kNotFound; if (++passed_elements == nof) return kNotFound;
} }
} }
...@@ -6503,9 +6497,8 @@ int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) { ...@@ -6503,9 +6497,8 @@ int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) {
} }
template<int prefix_size, int element_size> template<typename Shape, typename Key>
Object* HashTable<prefix_size, element_size>::EnsureCapacity( Object* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
int n, HashTableKey* key) {
int capacity = Capacity(); int capacity = Capacity();
int nof = NumberOfElements() + n; int nof = NumberOfElements() + n;
// Make sure 50% is free // Make sure 50% is free
...@@ -6517,18 +6510,20 @@ Object* HashTable<prefix_size, element_size>::EnsureCapacity( ...@@ -6517,18 +6510,20 @@ Object* HashTable<prefix_size, element_size>::EnsureCapacity(
WriteBarrierMode mode = table->GetWriteBarrierMode(); WriteBarrierMode mode = table->GetWriteBarrierMode();
// Copy prefix to new array. // Copy prefix to new array.
for (int i = kPrefixStartIndex; i < kPrefixStartIndex + prefix_size; i++) { for (int i = kPrefixStartIndex;
i < kPrefixStartIndex + Shape::kPrefixSize;
i++) {
table->set(i, get(i), mode); table->set(i, get(i), mode);
} }
// Rehash the elements. // Rehash the elements.
uint32_t (*Hash)(Object* key) = key->GetHashFunction();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
uint32_t from_index = EntryToIndex(i); uint32_t from_index = EntryToIndex(i);
Object* key = get(from_index); Object* k = get(from_index);
if (IsKey(key)) { if (IsKey(k)) {
uint32_t hash = Shape::HashForObject(key, k);
uint32_t insertion_index = uint32_t insertion_index =
EntryToIndex(table->FindInsertionEntry(key, Hash(key))); EntryToIndex(table->FindInsertionEntry(hash));
for (int j = 0; j < element_size; j++) { for (int j = 0; j < Shape::kEntrySize; j++) {
table->set(insertion_index + j, get(from_index + j), mode); table->set(insertion_index + j, get(from_index + j), mode);
} }
} }
...@@ -6538,10 +6533,8 @@ Object* HashTable<prefix_size, element_size>::EnsureCapacity( ...@@ -6538,10 +6533,8 @@ Object* HashTable<prefix_size, element_size>::EnsureCapacity(
} }
template<int prefix_size, int element_size> template<typename Shape, typename Key>
uint32_t HashTable<prefix_size, element_size>::FindInsertionEntry( uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
Object* key,
uint32_t hash) {
uint32_t capacity = Capacity(); uint32_t capacity = Capacity();
uint32_t entry = GetProbe(hash, 0, capacity); uint32_t entry = GetProbe(hash, 0, capacity);
Object* element = KeyAt(entry); Object* element = KeyAt(entry);
...@@ -6554,18 +6547,23 @@ uint32_t HashTable<prefix_size, element_size>::FindInsertionEntry( ...@@ -6554,18 +6547,23 @@ uint32_t HashTable<prefix_size, element_size>::FindInsertionEntry(
return entry; return entry;
} }
// Force instantiation of template instances class
template class HashTable<SymbolTableShape, HashTableKey*>;
// Force instantiation of SymbolTable's base class template class HashTable<CompilationCacheShape, HashTableKey*>;
template class HashTable<0, 1>;
template class HashTable<MapCacheShape, HashTableKey*>;
// Force instantiation of Dictionary's base class template class Dictionary<StringDictionaryShape, String*>;
template class HashTable<2, 3>;
template class Dictionary<NumberDictionaryShape, uint32_t>;
// Force instantiation of EvalCache's base class
template class HashTable<0, 2>;
template Object* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
int at_least_space_for);
template Object* Dictionary<StringDictionaryShape, String*>::Allocate(
int at_least_space_for);
// Collates undefined and unexisting elements below limit from position // Collates undefined and unexisting elements below limit from position
// zero of the elements. The object stays in Dictionary mode. // zero of the elements. The object stays in Dictionary mode.
...@@ -6574,7 +6572,7 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { ...@@ -6574,7 +6572,7 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
// Must stay in dictionary mode, either because of requires_slow_elements, // Must stay in dictionary mode, either because of requires_slow_elements,
// or because we are not going to sort (and therefore compact) all of the // or because we are not going to sort (and therefore compact) all of the
// elements. // elements.
Dictionary* dict = element_dictionary(); NumberDictionary* dict = element_dictionary();
HeapNumber* result_double = NULL; HeapNumber* result_double = NULL;
if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
// Allocate space for result before we start mutating the object. // Allocate space for result before we start mutating the object.
...@@ -6584,9 +6582,9 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { ...@@ -6584,9 +6582,9 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
} }
int capacity = dict->Capacity(); int capacity = dict->Capacity();
Object* obj = Dictionary::Allocate(dict->Capacity()); Object* obj = NumberDictionary::Allocate(dict->Capacity());
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
Dictionary* new_dict = Dictionary::cast(obj); NumberDictionary* new_dict = NumberDictionary::cast(obj);
AssertNoAllocation no_alloc; AssertNoAllocation no_alloc;
...@@ -6647,7 +6645,7 @@ Object* JSObject::PrepareElementsForSort(uint32_t limit) { ...@@ -6647,7 +6645,7 @@ Object* JSObject::PrepareElementsForSort(uint32_t limit) {
if (!HasFastElements()) { if (!HasFastElements()) {
// Convert to fast elements containing only the existing properties. // Convert to fast elements containing only the existing properties.
// Ordering is irrelevant, since we are going to sort anyway. // Ordering is irrelevant, since we are going to sort anyway.
Dictionary* dict = element_dictionary(); NumberDictionary* dict = element_dictionary();
if (IsJSArray() || dict->requires_slow_elements() || if (IsJSArray() || dict->requires_slow_elements() ||
dict->max_number_key() >= limit) { dict->max_number_key() >= limit) {
return PrepareSlowElementsForSort(limit); return PrepareSlowElementsForSort(limit);
...@@ -6787,7 +6785,7 @@ Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) { ...@@ -6787,7 +6785,7 @@ Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
// Create symbol object. // Create symbol object.
Object* symbol = key->GetObject(); Object* symbol = key->AsObject();
if (symbol->IsFailure()) return symbol; if (symbol->IsFailure()) return symbol;
// If the symbol table grew as part of EnsureCapacity, obj is not // If the symbol table grew as part of EnsureCapacity, obj is not
...@@ -6796,7 +6794,7 @@ Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) { ...@@ -6796,7 +6794,7 @@ Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
SymbolTable* table = reinterpret_cast<SymbolTable*>(obj); SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
// Add the new symbol and return it along with the symbol table. // Add the new symbol and return it along with the symbol table.
entry = table->FindInsertionEntry(symbol, key->Hash()); entry = table->FindInsertionEntry(key->Hash());
table->set(EntryToIndex(entry), symbol); table->set(EntryToIndex(entry), symbol);
table->ElementAdded(); table->ElementAdded();
*s = symbol; *s = symbol;
...@@ -6836,7 +6834,7 @@ Object* CompilationCacheTable::Put(String* src, Object* value) { ...@@ -6836,7 +6834,7 @@ Object* CompilationCacheTable::Put(String* src, Object* value) {
CompilationCacheTable* cache = CompilationCacheTable* cache =
reinterpret_cast<CompilationCacheTable*>(obj); reinterpret_cast<CompilationCacheTable*>(obj);
int entry = cache->FindInsertionEntry(src, key.Hash()); int entry = cache->FindInsertionEntry(key.Hash());
cache->set(EntryToIndex(entry), src); cache->set(EntryToIndex(entry), src);
cache->set(EntryToIndex(entry) + 1, value); cache->set(EntryToIndex(entry) + 1, value);
cache->ElementAdded(); cache->ElementAdded();
...@@ -6853,9 +6851,9 @@ Object* CompilationCacheTable::PutEval(String* src, ...@@ -6853,9 +6851,9 @@ Object* CompilationCacheTable::PutEval(String* src,
CompilationCacheTable* cache = CompilationCacheTable* cache =
reinterpret_cast<CompilationCacheTable*>(obj); reinterpret_cast<CompilationCacheTable*>(obj);
int entry = cache->FindInsertionEntry(src, key.Hash()); int entry = cache->FindInsertionEntry(key.Hash());
Object* k = key.GetObject(); Object* k = key.AsObject();
if (k->IsFailure()) return k; if (k->IsFailure()) return k;
cache->set(EntryToIndex(entry), k); cache->set(EntryToIndex(entry), k);
...@@ -6874,7 +6872,7 @@ Object* CompilationCacheTable::PutRegExp(String* src, ...@@ -6874,7 +6872,7 @@ Object* CompilationCacheTable::PutRegExp(String* src,
CompilationCacheTable* cache = CompilationCacheTable* cache =
reinterpret_cast<CompilationCacheTable*>(obj); reinterpret_cast<CompilationCacheTable*>(obj);
int entry = cache->FindInsertionEntry(value, key.Hash()); int entry = cache->FindInsertionEntry(key.Hash());
cache->set(EntryToIndex(entry), value); cache->set(EntryToIndex(entry), value);
cache->set(EntryToIndex(entry) + 1, value); cache->set(EntryToIndex(entry) + 1, value);
cache->ElementAdded(); cache->ElementAdded();
...@@ -6897,13 +6895,9 @@ class SymbolsKey : public HashTableKey { ...@@ -6897,13 +6895,9 @@ class SymbolsKey : public HashTableKey {
return true; return true;
} }
uint32_t Hash() { return SymbolsHash(symbols_); } uint32_t Hash() { return HashForObject(symbols_); }
HashFunction GetHashFunction() { return SymbolsHash; }
Object* GetObject() { return symbols_; } uint32_t HashForObject(Object* obj) {
static uint32_t SymbolsHash(Object* obj) {
FixedArray* symbols = FixedArray::cast(obj); FixedArray* symbols = FixedArray::cast(obj);
int len = symbols->length(); int len = symbols->length();
uint32_t hash = 0; uint32_t hash = 0;
...@@ -6913,7 +6907,7 @@ class SymbolsKey : public HashTableKey { ...@@ -6913,7 +6907,7 @@ class SymbolsKey : public HashTableKey {
return hash; return hash;
} }
bool IsStringKey() { return false; } Object* AsObject() { return symbols_; }
private: private:
FixedArray* symbols_; FixedArray* symbols_;
...@@ -6934,7 +6928,7 @@ Object* MapCache::Put(FixedArray* array, Map* value) { ...@@ -6934,7 +6928,7 @@ Object* MapCache::Put(FixedArray* array, Map* value) {
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
MapCache* cache = reinterpret_cast<MapCache*>(obj); MapCache* cache = reinterpret_cast<MapCache*>(obj);
int entry = cache->FindInsertionEntry(array, key.Hash()); int entry = cache->FindInsertionEntry(key.Hash());
cache->set(EntryToIndex(entry), array); cache->set(EntryToIndex(entry), array);
cache->set(EntryToIndex(entry) + 1, value); cache->set(EntryToIndex(entry) + 1, value);
cache->ElementAdded(); cache->ElementAdded();
...@@ -6942,19 +6936,21 @@ Object* MapCache::Put(FixedArray* array, Map* value) { ...@@ -6942,19 +6936,21 @@ Object* MapCache::Put(FixedArray* array, Map* value) {
} }
Object* Dictionary::Allocate(int at_least_space_for) { template<typename Shape, typename Key>
Object* obj = DictionaryBase::Allocate(at_least_space_for); Object* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
Object* obj = HashTable<Shape, Key>::Allocate(at_least_space_for);
// Initialize the next enumeration index. // Initialize the next enumeration index.
if (!obj->IsFailure()) { if (!obj->IsFailure()) {
Dictionary::cast(obj)-> Dictionary<Shape, Key>::cast(obj)->
SetNextEnumerationIndex(PropertyDetails::kInitialIndex); SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
} }
return obj; return obj;
} }
Object* Dictionary::GenerateNewEnumerationIndices() { template<typename Shape, typename Key>
int length = NumberOfElements(); Object* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
int length = HashTable<Shape, Key>::NumberOfElements();
// Allocate and initialize iteration order array. // Allocate and initialize iteration order array.
Object* obj = Heap::AllocateFixedArray(length); Object* obj = Heap::AllocateFixedArray(length);
...@@ -6970,10 +6966,10 @@ Object* Dictionary::GenerateNewEnumerationIndices() { ...@@ -6970,10 +6966,10 @@ Object* Dictionary::GenerateNewEnumerationIndices() {
FixedArray* enumeration_order = FixedArray::cast(obj); FixedArray* enumeration_order = FixedArray::cast(obj);
// Fill the enumeration order array with property details. // Fill the enumeration order array with property details.
int capacity = Capacity(); int capacity = HashTable<Shape, Key>::Capacity();
int pos = 0; int pos = 0;
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
if (IsKey(KeyAt(i))) { if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
enumeration_order->set(pos++, enumeration_order->set(pos++,
Smi::FromInt(DetailsAt(i).index()), Smi::FromInt(DetailsAt(i).index()),
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
...@@ -6993,10 +6989,10 @@ Object* Dictionary::GenerateNewEnumerationIndices() { ...@@ -6993,10 +6989,10 @@ Object* Dictionary::GenerateNewEnumerationIndices() {
} }
// Update the dictionary with new indices. // Update the dictionary with new indices.
capacity = Capacity(); capacity = HashTable<Shape, Key>::Capacity();
pos = 0; pos = 0;
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
if (IsKey(KeyAt(i))) { if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
int enum_index = Smi::cast(enumeration_order->get(pos++))->value(); int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
PropertyDetails details = DetailsAt(i); PropertyDetails details = DetailsAt(i);
PropertyDetails new_details = PropertyDetails new_details =
...@@ -7010,20 +7006,20 @@ Object* Dictionary::GenerateNewEnumerationIndices() { ...@@ -7010,20 +7006,20 @@ Object* Dictionary::GenerateNewEnumerationIndices() {
return this; return this;
} }
template<typename Shape, typename Key>
Object* Dictionary::EnsureCapacity(int n, HashTableKey* key) { Object* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
// Check whether there are enough enumeration indices to add n elements. // Check whether there are enough enumeration indices to add n elements.
if (key->IsStringKey() && if (Shape::kIsEnumerable &&
!PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) { !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
// If not, we generate new indices for the properties. // If not, we generate new indices for the properties.
Object* result = GenerateNewEnumerationIndices(); Object* result = GenerateNewEnumerationIndices();
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
} }
return DictionaryBase::EnsureCapacity(n, key); return HashTable<Shape, Key>::EnsureCapacity(n, key);
} }
void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
// Do nothing if the interval [from, to) is empty. // Do nothing if the interval [from, to) is empty.
if (from >= to) return; if (from >= to) return;
...@@ -7045,36 +7041,26 @@ void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { ...@@ -7045,36 +7041,26 @@ void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
SetNumberOfElements(NumberOfElements() - removed_entries); SetNumberOfElements(NumberOfElements() - removed_entries);
} }
template<typename Shape, typename Key>
Object* Dictionary::DeleteProperty(int entry, JSObject::DeleteMode mode) { Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
JSObject::DeleteMode mode) {
PropertyDetails details = DetailsAt(entry); PropertyDetails details = DetailsAt(entry);
// Ignore attributes if forcing a deletion. // Ignore attributes if forcing a deletion.
if (details.IsDontDelete() && mode == JSObject::NORMAL_DELETION) { if (details.IsDontDelete() && mode == JSObject::NORMAL_DELETION) {
return Heap::false_value(); return Heap::false_value();
} }
SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0)); SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
ElementRemoved(); HashTable<Shape, Key>::ElementRemoved();
return Heap::true_value(); return Heap::true_value();
} }
int Dictionary::FindStringEntry(String* key) { template<typename Shape, typename Key>
StringKey k(key); Object* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
return FindEntry(&k);
}
int Dictionary::FindNumberEntry(uint32_t index) {
NumberKey k(index);
return FindEntry(&k);
}
Object* Dictionary::AtPut(HashTableKey* key, Object* value) {
int entry = FindEntry(key); int entry = FindEntry(key);
// If the entry is present set the value; // If the entry is present set the value;
if (entry != kNotFound) { if (entry != Dictionary<Shape, Key>::kNotFound) {
ValueAtPut(entry, value); ValueAtPut(entry, value);
return this; return this;
} }
...@@ -7082,48 +7068,57 @@ Object* Dictionary::AtPut(HashTableKey* key, Object* value) { ...@@ -7082,48 +7068,57 @@ Object* Dictionary::AtPut(HashTableKey* key, Object* value) {
// Check whether the dictionary should be extended. // Check whether the dictionary should be extended.
Object* obj = EnsureCapacity(1, key); Object* obj = EnsureCapacity(1, key);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
Object* k = key->GetObject();
Object* k = Shape::AsObject(key);
if (k->IsFailure()) return k; if (k->IsFailure()) return k;
PropertyDetails details = PropertyDetails(NONE, NORMAL); PropertyDetails details = PropertyDetails(NONE, NORMAL);
Dictionary::cast(obj)->AddEntry(k, value, details, key->Hash()); return Dictionary<Shape, Key>::cast(obj)->
return obj; AddEntry(key, value, details, Shape::Hash(key));
} }
Object* Dictionary::Add(HashTableKey* key, Object* value, template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::Add(Key key,
Object* value,
PropertyDetails details) { PropertyDetails details) {
// Valdate key is absent.
SLOW_ASSERT((FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
// Check whether the dictionary should be extended. // Check whether the dictionary should be extended.
Object* obj = EnsureCapacity(1, key); Object* obj = EnsureCapacity(1, key);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
// Compute the key object. return Dictionary<Shape, Key>::cast(obj)->
Object* k = key->GetObject(); AddEntry(key, value, details, Shape::Hash(key));
if (k->IsFailure()) return k;
Dictionary::cast(obj)->AddEntry(k, value, details, key->Hash());
return obj;
} }
// Add a key, value pair to the dictionary. // Add a key, value pair to the dictionary.
void Dictionary::AddEntry(Object* key, template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::AddEntry(Key key,
Object* value, Object* value,
PropertyDetails details, PropertyDetails details,
uint32_t hash) { uint32_t hash) {
uint32_t entry = FindInsertionEntry(key, hash); // Compute the key object.
Object* k = Shape::AsObject(key);
if (k->IsFailure()) return k;
uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
// Insert element at empty or deleted entry // Insert element at empty or deleted entry
if (details.index() == 0 && key->IsString()) { if (details.index() == 0 && Shape::kIsEnumerable) {
// Assign an enumeration index to the property and update // Assign an enumeration index to the property and update
// SetNextEnumerationIndex. // SetNextEnumerationIndex.
int index = NextEnumerationIndex(); int index = NextEnumerationIndex();
details = PropertyDetails(details.attributes(), details.type(), index); details = PropertyDetails(details.attributes(), details.type(), index);
SetNextEnumerationIndex(index + 1); SetNextEnumerationIndex(index + 1);
} }
SetEntry(entry, key, value, details); SetEntry(entry, k, value, details);
ASSERT(KeyAt(entry)->IsNumber() || KeyAt(entry)->IsString()); ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
ElementAdded(); || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
HashTable<Shape, Key>::ElementAdded();
return this;
} }
void Dictionary::UpdateMaxNumberKey(uint32_t key) { void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
// If the dictionary requires slow elements an element has already // If the dictionary requires slow elements an element has already
// been added at a high index. // been added at a high index.
if (requires_slow_elements()) return; if (requires_slow_elements()) return;
...@@ -7136,73 +7131,51 @@ void Dictionary::UpdateMaxNumberKey(uint32_t key) { ...@@ -7136,73 +7131,51 @@ void Dictionary::UpdateMaxNumberKey(uint32_t key) {
// Update max key value. // Update max key value.
Object* max_index_object = get(kMaxNumberKeyIndex); Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi() || max_number_key() < key) { if (!max_index_object->IsSmi() || max_number_key() < key) {
set(kMaxNumberKeyIndex, FixedArray::set(kMaxNumberKeyIndex,
Smi::FromInt(key << kRequiresSlowElementsTagSize), Smi::FromInt(key << kRequiresSlowElementsTagSize),
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
} }
} }
Object* Dictionary::AddStringEntry(String* key, Object* NumberDictionary::AddNumberEntry(uint32_t key,
Object* value, Object* value,
PropertyDetails details) { PropertyDetails details) {
StringKey k(key);
SLOW_ASSERT(FindEntry(&k) == kNotFound);
return Add(&k, value, details);
}
Object* Dictionary::AddNumberEntry(uint32_t key,
Object* value,
PropertyDetails details) {
NumberKey k(key);
UpdateMaxNumberKey(key); UpdateMaxNumberKey(key);
SLOW_ASSERT(FindEntry(&k) == kNotFound); SLOW_ASSERT(FindEntry(key) == kNotFound);
return Add(&k, value, details); return Add(key, value, details);
} }
Object* Dictionary::AtNumberPut(uint32_t key, Object* value) { Object* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
NumberKey k(key);
UpdateMaxNumberKey(key); UpdateMaxNumberKey(key);
return AtPut(&k, value); return AtPut(key, value);
} }
Object* Dictionary::SetStringEntry(int entry, Object* NumberDictionary::Set(uint32_t key,
String* key,
Object* value, Object* value,
PropertyDetails details) { PropertyDetails details) {
int entry = FindEntry(key);
if (entry == kNotFound) return AddNumberEntry(key, value, details);
// Preserve enumeration index. // Preserve enumeration index.
details = PropertyDetails(details.attributes(), details = PropertyDetails(details.attributes(),
details.type(), details.type(),
DetailsAt(entry).index()); DetailsAt(entry).index());
SetEntry(entry, key, value, details); SetEntry(entry, NumberDictionaryShape::AsObject(key), value, details);
return this; return this;
} }
Object* Dictionary::SetOrAddNumberEntry(uint32_t key,
Object* value,
PropertyDetails details) {
NumberKey k(key);
int entry = FindEntry(&k);
if (entry == -1) return AddNumberEntry(key, value, details);
// Preserve enumeration index.
details = PropertyDetails(details.attributes(),
details.type(),
DetailsAt(entry).index());
SetEntry(entry, k.GetObject(), value, details);
return this;
}
int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) { template<typename Shape, typename Key>
int capacity = Capacity(); int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
PropertyAttributes filter) {
int capacity = HashTable<Shape, Key>::Capacity();
int result = 0; int result = 0;
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i); Object* k = HashTable<Shape, Key>::KeyAt(i);
if (IsKey(k)) { if (HashTable<Shape, Key>::IsKey(k)) {
PropertyAttributes attr = DetailsAt(i).attributes(); PropertyAttributes attr = DetailsAt(i).attributes();
if ((attr & filter) == 0) result++; if ((attr & filter) == 0) result++;
} }
...@@ -7211,19 +7184,22 @@ int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) { ...@@ -7211,19 +7184,22 @@ int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) {
} }
int Dictionary::NumberOfEnumElements() { template<typename Shape, typename Key>
int Dictionary<Shape, Key>::NumberOfEnumElements() {
return NumberOfElementsFilterAttributes( return NumberOfElementsFilterAttributes(
static_cast<PropertyAttributes>(DONT_ENUM)); static_cast<PropertyAttributes>(DONT_ENUM));
} }
void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) { template<typename Shape, typename Key>
void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
PropertyAttributes filter) {
ASSERT(storage->length() >= NumberOfEnumElements()); ASSERT(storage->length() >= NumberOfEnumElements());
int capacity = Capacity(); int capacity = HashTable<Shape, Key>::Capacity();
int index = 0; int index = 0;
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i); Object* k = HashTable<Shape, Key>::KeyAt(i);
if (IsKey(k)) { if (HashTable<Shape, Key>::IsKey(k)) {
PropertyAttributes attr = DetailsAt(i).attributes(); PropertyAttributes attr = DetailsAt(i).attributes();
if ((attr & filter) == 0) storage->set(index++, k); if ((attr & filter) == 0) storage->set(index++, k);
} }
...@@ -7233,7 +7209,8 @@ void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) { ...@@ -7233,7 +7209,8 @@ void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) {
} }
void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) { void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
FixedArray* sort_array) {
ASSERT(storage->length() >= NumberOfEnumElements()); ASSERT(storage->length() >= NumberOfEnumElements());
int capacity = Capacity(); int capacity = Capacity();
int index = 0; int index = 0;
...@@ -7255,14 +7232,15 @@ void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) { ...@@ -7255,14 +7232,15 @@ void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) {
} }
void Dictionary::CopyKeysTo(FixedArray* storage) { template<typename Shape, typename Key>
void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
ASSERT(storage->length() >= NumberOfElementsFilterAttributes( ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
static_cast<PropertyAttributes>(NONE))); static_cast<PropertyAttributes>(NONE)));
int capacity = Capacity(); int capacity = HashTable<Shape, Key>::Capacity();
int index = 0; int index = 0;
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i); Object* k = HashTable<Shape, Key>::KeyAt(i);
if (IsKey(k)) { if (HashTable<Shape, Key>::IsKey(k)) {
storage->set(index++, k); storage->set(index++, k);
} }
} }
...@@ -7271,11 +7249,12 @@ void Dictionary::CopyKeysTo(FixedArray* storage) { ...@@ -7271,11 +7249,12 @@ void Dictionary::CopyKeysTo(FixedArray* storage) {
// Backwards lookup (slow). // Backwards lookup (slow).
Object* Dictionary::SlowReverseLookup(Object* value) { template<typename Shape, typename Key>
int capacity = Capacity(); Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
int capacity = HashTable<Shape, Key>::Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i); Object* k = HashTable<Shape, Key>::KeyAt(i);
if (IsKey(k)) { if (Dictionary<Shape, Key>::IsKey(k)) {
Object* e = ValueAt(i); Object* e = ValueAt(i);
if (e->IsJSGlobalPropertyCell()) { if (e->IsJSGlobalPropertyCell()) {
e = JSGlobalPropertyCell::cast(e)->value(); e = JSGlobalPropertyCell::cast(e)->value();
...@@ -7287,8 +7266,8 @@ Object* Dictionary::SlowReverseLookup(Object* value) { ...@@ -7287,8 +7266,8 @@ Object* Dictionary::SlowReverseLookup(Object* value) {
} }
Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, Object* StringDictionary::TransformPropertiesToFastFor(
int unused_property_fields) { JSObject* obj, int unused_property_fields) {
// Make sure we preserve dictionary representation if there are too many // Make sure we preserve dictionary representation if there are too many
// descriptors. // descriptors.
if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj; if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
...@@ -7296,7 +7275,8 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, ...@@ -7296,7 +7275,8 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj,
// Figure out if it is necessary to generate new enumeration indices. // Figure out if it is necessary to generate new enumeration indices.
int max_enumeration_index = int max_enumeration_index =
NextEnumerationIndex() + NextEnumerationIndex() +
(DescriptorArray::kMaxNumberOfDescriptors - NumberOfElements()); (DescriptorArray::kMaxNumberOfDescriptors -
NumberOfElements());
if (!PropertyDetails::IsValidIndex(max_enumeration_index)) { if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
Object* result = GenerateNewEnumerationIndices(); Object* result = GenerateNewEnumerationIndices();
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
...@@ -7645,4 +7625,5 @@ int BreakPointInfo::GetBreakPointCount() { ...@@ -7645,4 +7625,5 @@ int BreakPointInfo::GetBreakPointCount() {
} }
#endif #endif
} } // namespace v8::internal } } // namespace v8::internal
...@@ -1207,7 +1207,7 @@ class JSObject: public HeapObject { ...@@ -1207,7 +1207,7 @@ class JSObject: public HeapObject {
DECL_ACCESSORS(properties, FixedArray) // Get and set fast properties. DECL_ACCESSORS(properties, FixedArray) // Get and set fast properties.
inline void initialize_properties(); inline void initialize_properties();
inline bool HasFastProperties(); inline bool HasFastProperties();
inline Dictionary* property_dictionary(); // Gets slow properties. inline StringDictionary* property_dictionary(); // Gets slow properties.
// [elements]: The elements (properties with names that are integers). // [elements]: The elements (properties with names that are integers).
// elements is a FixedArray in the fast case, and a Dictionary in the slow // elements is a FixedArray in the fast case, and a Dictionary in the slow
...@@ -1215,7 +1215,7 @@ class JSObject: public HeapObject { ...@@ -1215,7 +1215,7 @@ class JSObject: public HeapObject {
DECL_ACCESSORS(elements, FixedArray) // Get and set fast elements. DECL_ACCESSORS(elements, FixedArray) // Get and set fast elements.
inline void initialize_elements(); inline void initialize_elements();
inline bool HasFastElements(); inline bool HasFastElements();
inline Dictionary* element_dictionary(); // Gets slow elements. inline NumberDictionary* element_dictionary(); // Gets slow elements.
// Collects elements starting at index 0. // Collects elements starting at index 0.
// Undefined values are placed after non-undefined values. // Undefined values are placed after non-undefined values.
...@@ -1875,32 +1875,29 @@ class DescriptorArray: public FixedArray { ...@@ -1875,32 +1875,29 @@ class DescriptorArray: public FixedArray {
// - Elements with key == undefined have not been used yet. // - Elements with key == undefined have not been used yet.
// - Elements with key == null have been deleted. // - Elements with key == null have been deleted.
// //
// The hash table class is parameterized with a prefix size and with // The hash table class is parameterized with a Shape and a Key.
// the size, including the key size, of the elements held in the hash // Shape must be a class with the following interface:
// class ExampleShape {
// public:
// // Tells whether key matches other.
// static bool IsMatch(Key key, Object* other);
// // Returns the hash value for key.
// static uint32_t Hash(Key key);
// // Returns the hash value for object.
// static uint32_t HashForObject(Key key, Object* object);
// // Convert key to an object.
// static inline Object* AsObject(Key key);
// // The prefix size indicates number of elements in the beginning
// // of the backing storage.
// static const int kPrefixSize = ..;
// // The Element size indicates number of elements per entry.
// static const int kEntrySize = ..;
// };
// table. The prefix size indicates an amount of memory in the // table. The prefix size indicates an amount of memory in the
// beginning of the backing storage that can be used for non-element // beginning of the backing storage that can be used for non-element
// information by subclasses. // information by subclasses.
// HashTableKey is an abstract superclass keys. template<typename Shape, typename Key>
class HashTableKey {
public:
// Returns whether the other object matches this key.
virtual bool IsMatch(Object* other) = 0;
typedef uint32_t (*HashFunction)(Object* obj);
// Returns the hash function used for this key.
virtual HashFunction GetHashFunction() = 0;
// Returns the hash value for this key.
virtual uint32_t Hash() = 0;
// Returns the key object for storing into the dictionary.
// If allocations fails a failure object is returned.
virtual Object* GetObject() = 0;
virtual bool IsStringKey() = 0;
// Required.
virtual ~HashTableKey() {}
};
template<int prefix_size, int element_size>
class HashTable: public FixedArray { class HashTable: public FixedArray {
public: public:
// Returns the number of elements in the dictionary. // Returns the number of elements in the dictionary.
...@@ -1949,25 +1946,27 @@ class HashTable: public FixedArray { ...@@ -1949,25 +1946,27 @@ class HashTable: public FixedArray {
static const int kNumberOfElementsIndex = 0; static const int kNumberOfElementsIndex = 0;
static const int kCapacityIndex = 1; static const int kCapacityIndex = 1;
static const int kPrefixStartIndex = 2; static const int kPrefixStartIndex = 2;
static const int kElementsStartIndex = kPrefixStartIndex + prefix_size; static const int kElementsStartIndex =
static const int kElementSize = element_size; kPrefixStartIndex + Shape::kPrefixSize;
static const int kEntrySize = Shape::kEntrySize;
static const int kElementsStartOffset = static const int kElementsStartOffset =
kHeaderSize + kElementsStartIndex * kPointerSize; kHeaderSize + kElementsStartIndex * kPointerSize;
// Constant used for denoting a absent entry. // Constant used for denoting a absent entry.
static const int kNotFound = -1; static const int kNotFound = -1;
protected:
// Find entry for key otherwise return -1. // Find entry for key otherwise return -1.
int FindEntry(HashTableKey* key); int FindEntry(Key key);
protected:
// Find the entry at which to insert element with the given key that // Find the entry at which to insert element with the given key that
// has the given hash value. // has the given hash value.
uint32_t FindInsertionEntry(Object* key, uint32_t hash); uint32_t FindInsertionEntry(uint32_t hash);
// Returns the index for an entry (of the key) // Returns the index for an entry (of the key)
static inline int EntryToIndex(int entry) { static inline int EntryToIndex(int entry) {
return (entry * kElementSize) + kElementsStartIndex; return (entry * kEntrySize) + kElementsStartIndex;
} }
// Update the number of elements in the dictionary. // Update the number of elements in the dictionary.
...@@ -1992,15 +1991,51 @@ class HashTable: public FixedArray { ...@@ -1992,15 +1991,51 @@ class HashTable: public FixedArray {
} }
// Ensure enough space for n additional elements. // Ensure enough space for n additional elements.
Object* EnsureCapacity(int n, HashTableKey* key); Object* EnsureCapacity(int n, Key key);
};
// HashTableKey is an abstract superclass for virtual key behavior.
class HashTableKey {
public:
// Returns whether the other object matches this key.
virtual bool IsMatch(Object* other) = 0;
// Returns the hash value for this key.
virtual uint32_t Hash() = 0;
// Returns the hash value for object.
virtual uint32_t HashForObject(Object* key) = 0;
// Returns the key object for storing into the dictionary.
// If allocations fails a failure object is returned.
virtual Object* AsObject() = 0;
// Required.
virtual ~HashTableKey() {}
}; };
class SymbolTableShape {
public:
static bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
}
static uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
static uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
}
static Object* AsObject(HashTableKey* key) {
return key->AsObject();
}
static const int kPrefixSize = 0;
static const int kEntrySize = 1;
};
// SymbolTable. // SymbolTable.
// //
// No special elements in the prefix and the element size is 1 // No special elements in the prefix and the element size is 1
// because only the symbol itself (the key) needs to be stored. // because only the symbol itself (the key) needs to be stored.
class SymbolTable: public HashTable<0, 1> { class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> {
public: public:
// Find symbol in the symbol table. If it is not there yet, it is // Find symbol in the symbol table. If it is not there yet, it is
// added. The return value is the symbol table which might have // added. The return value is the symbol table which might have
...@@ -2024,11 +2059,33 @@ class SymbolTable: public HashTable<0, 1> { ...@@ -2024,11 +2059,33 @@ class SymbolTable: public HashTable<0, 1> {
}; };
class MapCacheShape {
public:
static bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
}
static uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
static uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
}
static Object* AsObject(HashTableKey* key) {
return key->AsObject();
}
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
};
// MapCache. // MapCache.
// //
// Maps keys that are a fixed array of symbols to a map. // Maps keys that are a fixed array of symbols to a map.
// Used for canonicalize maps for object literals. // Used for canonicalize maps for object literals.
class MapCache: public HashTable<0, 2> { class MapCache: public HashTable<MapCacheShape, HashTableKey*> {
public: public:
// Find cached value for a string key, otherwise return null. // Find cached value for a string key, otherwise return null.
Object* Lookup(FixedArray* key); Object* Lookup(FixedArray* key);
...@@ -2040,74 +2097,42 @@ class MapCache: public HashTable<0, 2> { ...@@ -2040,74 +2097,42 @@ class MapCache: public HashTable<0, 2> {
}; };
// Dictionary for keeping properties and elements in slow case. template <typename Shape, typename Key>
// class Dictionary: public HashTable<Shape, Key> {
// One element in the prefix is used for storing non-element
// information about the dictionary.
//
// The rest of the array embeds triples of (key, value, details).
// if key == undefined the triple is empty.
// if key == null the triple has been deleted.
// otherwise key contains the name of a property.
class DictionaryBase: public HashTable<2, 3> {};
class Dictionary: public DictionaryBase {
public: public:
static inline Dictionary<Shape, Key>* cast(Object* obj) {
return reinterpret_cast<Dictionary<Shape, Key>*>(obj);
}
// Returns the value at entry. // Returns the value at entry.
Object* ValueAt(int entry) { Object* ValueAt(int entry) {
return get(EntryToIndex(entry)+1); return get(HashTable<Shape, Key>::EntryToIndex(entry)+1);
} }
// Set the value for entry. // Set the value for entry.
void ValueAtPut(int entry, Object* value) { void ValueAtPut(int entry, Object* value) {
set(EntryToIndex(entry)+1, value); set(HashTable<Shape, Key>::EntryToIndex(entry)+1, value);
} }
// Returns the property details for the property at entry. // Returns the property details for the property at entry.
PropertyDetails DetailsAt(int entry) { PropertyDetails DetailsAt(int entry) {
ASSERT(entry >= 0); // Not found is -1, which is not caught by get(). ASSERT(entry >= 0); // Not found is -1, which is not caught by get().
return PropertyDetails(Smi::cast(get(EntryToIndex(entry) + 2))); return PropertyDetails(
Smi::cast(get(HashTable<Shape, Key>::EntryToIndex(entry) + 2)));
} }
// Set the details for entry. // Set the details for entry.
void DetailsAtPut(int entry, PropertyDetails value) { void DetailsAtPut(int entry, PropertyDetails value) {
set(EntryToIndex(entry) + 2, value.AsSmi()); set(HashTable<Shape, Key>::EntryToIndex(entry) + 2, value.AsSmi());
} }
// Remove all entries were key is a number and (from <= key && key < to).
void RemoveNumberEntries(uint32_t from, uint32_t to);
// Sorting support // Sorting support
void CopyValuesTo(FixedArray* elements); void CopyValuesTo(FixedArray* elements);
// Casting.
static inline Dictionary* cast(Object* obj);
// Find entry for string key otherwise return -1.
int FindStringEntry(String* key);
// Find entry for number key otherwise return -1.
int FindNumberEntry(uint32_t index);
// Delete a property from the dictionary. // Delete a property from the dictionary.
Object* DeleteProperty(int entry, JSObject::DeleteMode mode); Object* DeleteProperty(int entry, JSObject::DeleteMode mode);
// Type specific at put (default NONE attributes is used when adding).
Object* AtNumberPut(uint32_t key, Object* value);
Object* AddStringEntry(String* key, Object* value, PropertyDetails details);
Object* AddNumberEntry(uint32_t key, Object* value, PropertyDetails details);
// Set an existing entry or add a new one if needed.
Object* SetStringEntry(int entry,
String* key,
Object* value,
PropertyDetails details);
Object* SetOrAddNumberEntry(uint32_t key,
Object* value,
PropertyDetails details);
// Returns the number of elements in the dictionary filtering out properties // Returns the number of elements in the dictionary filtering out properties
// with the specified attributes. // with the specified attributes.
int NumberOfElementsFilterAttributes(PropertyAttributes filter); int NumberOfElementsFilterAttributes(PropertyAttributes filter);
...@@ -2117,42 +2142,23 @@ class Dictionary: public DictionaryBase { ...@@ -2117,42 +2142,23 @@ class Dictionary: public DictionaryBase {
// Copies keys to preallocated fixed array. // Copies keys to preallocated fixed array.
void CopyKeysTo(FixedArray* storage, PropertyAttributes filter); void CopyKeysTo(FixedArray* storage, PropertyAttributes filter);
// Copies enumerable keys to preallocated fixed array.
void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array);
// Fill in details for properties into storage. // Fill in details for properties into storage.
void CopyKeysTo(FixedArray* storage); void CopyKeysTo(FixedArray* storage);
// For transforming properties of a JSObject.
Object* TransformPropertiesToFastFor(JSObject* obj,
int unused_property_fields);
// If slow elements are required we will never go back to fast-case
// for the elements kept in this dictionary. We require slow
// elements if an element has been added at an index larger than
// kRequiresSlowElementsLimit or set_requires_slow_elements() has been called
// when defining a getter or setter with a number key.
inline bool requires_slow_elements();
inline void set_requires_slow_elements();
// Get the value of the max number key that has been added to this
// dictionary. max_number_key can only be called if
// requires_slow_elements returns false.
inline uint32_t max_number_key();
// Accessors for next enumeration index. // Accessors for next enumeration index.
void SetNextEnumerationIndex(int index) { void SetNextEnumerationIndex(int index) {
fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index)); fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index));
} }
int NextEnumerationIndex() { int NextEnumerationIndex() {
return Smi::cast(get(kNextEnumerationIndexIndex))->value(); return Smi::cast(FixedArray::get(kNextEnumerationIndexIndex))->value();
} }
// Returns a new array for dictionary usage. Might return Failure. // Returns a new array for dictionary usage. Might return Failure.
static Object* Allocate(int at_least_space_for); static Object* Allocate(int at_least_space_for);
// Ensure enough space for n additional elements. // Ensure enough space for n additional elements.
Object* EnsureCapacity(int n, HashTableKey* key); Object* EnsureCapacity(int n, Key key);
#ifdef DEBUG #ifdef DEBUG
void Print(); void Print();
...@@ -2160,38 +2166,110 @@ class Dictionary: public DictionaryBase { ...@@ -2160,38 +2166,110 @@ class Dictionary: public DictionaryBase {
// Returns the key (slow). // Returns the key (slow).
Object* SlowReverseLookup(Object* value); Object* SlowReverseLookup(Object* value);
// Bit masks. // Sets the entry to (key, value) pair.
static const int kRequiresSlowElementsMask = 1; inline void SetEntry(int entry,
static const int kRequiresSlowElementsTagSize = 1; Object* key,
static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1; Object* value,
PropertyDetails details);
void UpdateMaxNumberKey(uint32_t key); Object* Add(Key key, Object* value, PropertyDetails details);
private: protected:
// Generic at put operation. // Generic at put operation.
Object* AtPut(HashTableKey* key, Object* value); Object* AtPut(Key key, Object* value);
Object* Add(HashTableKey* key, Object* value, PropertyDetails details);
// Add entry to dictionary. // Add entry to dictionary.
void AddEntry(Object* key, Object* AddEntry(Key key,
Object* value, Object* value,
PropertyDetails details, PropertyDetails details,
uint32_t hash); uint32_t hash);
// Sets the entry to (key, value) pair. // Generate new enumeration indices to avoid enumeration index overflow.
inline void SetEntry(int entry, Object* GenerateNewEnumerationIndices();
Object* key, static const int kMaxNumberKeyIndex =
HashTable<Shape, Key>::kPrefixStartIndex;
static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
};
class StringDictionaryShape {
public:
static inline bool IsMatch(String* key, Object* other);
static inline uint32_t Hash(String* key);
static inline uint32_t HashForObject(String* key, Object* object);
static inline Object* AsObject(String* key);
static const int kPrefixSize = 2;
static const int kEntrySize = 3;
static const bool kIsEnumerable = true;
};
class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
public:
static inline StringDictionary* cast(Object* obj) {
ASSERT(obj->IsDictionary());
return reinterpret_cast<StringDictionary*>(obj);
}
// Copies enumerable keys to preallocated fixed array.
void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array);
// For transforming properties of a JSObject.
Object* TransformPropertiesToFastFor(JSObject* obj,
int unused_property_fields);
};
class NumberDictionaryShape {
public:
static inline bool IsMatch(uint32_t key, Object* other);
static inline uint32_t Hash(uint32_t key);
static inline uint32_t HashForObject(uint32_t key, Object* object);
static inline Object* AsObject(uint32_t key);
static const int kPrefixSize = 2;
static const int kEntrySize = 3;
static const bool kIsEnumerable = false;
};
class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
public:
static NumberDictionary* cast(Object* obj) {
ASSERT(obj->IsDictionary());
return reinterpret_cast<NumberDictionary*>(obj);
}
// Type specific at put (default NONE attributes is used when adding).
Object* AtNumberPut(uint32_t key, Object* value);
Object* AddNumberEntry(uint32_t key,
Object* value, Object* value,
PropertyDetails details); PropertyDetails details);
// Generate new enumeration indices to avoid enumeration index overflow. // Set an existing entry or add a new one if needed.
Object* GenerateNewEnumerationIndices(); Object* Set(uint32_t key, Object* value, PropertyDetails details);
static const int kMaxNumberKeyIndex = kPrefixStartIndex; void UpdateMaxNumberKey(uint32_t key);
static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary); // If slow elements are required we will never go back to fast-case
// for the elements kept in this dictionary. We require slow
// elements if an element has been added at an index larger than
// kRequiresSlowElementsLimit or set_requires_slow_elements() has been called
// when defining a getter or setter with a number key.
inline bool requires_slow_elements();
inline void set_requires_slow_elements();
// Get the value of the max number key that has been added to this
// dictionary. max_number_key can only be called if
// requires_slow_elements returns false.
inline uint32_t max_number_key();
// Remove all entries were key is a number and (from <= key && key < to).
void RemoveNumberEntries(uint32_t from, uint32_t to);
// Bit masks.
static const int kRequiresSlowElementsMask = 1;
static const int kRequiresSlowElementsTagSize = 1;
static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1;
}; };
...@@ -3231,7 +3309,30 @@ class JSRegExp: public JSObject { ...@@ -3231,7 +3309,30 @@ class JSRegExp: public JSObject {
}; };
class CompilationCacheTable: public HashTable<0, 2> { class CompilationCacheShape {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
}
static inline uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
}
static Object* AsObject(HashTableKey* key) {
return key->AsObject();
}
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
};
class CompilationCacheTable: public HashTable<CompilationCacheShape,
HashTableKey*> {
public: public:
// Find cached value for a string key, otherwise return null. // Find cached value for a string key, otherwise return null.
Object* Lookup(String* src); Object* Lookup(String* src);
......
...@@ -168,7 +168,7 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) { ...@@ -168,7 +168,7 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
} }
} }
} else { } else {
Dictionary* element_dictionary = copy->element_dictionary(); NumberDictionary* element_dictionary = copy->element_dictionary();
int capacity = element_dictionary->Capacity(); int capacity = element_dictionary->Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = element_dictionary->KeyAt(i); Object* k = element_dictionary->KeyAt(i);
...@@ -2604,9 +2604,9 @@ static Object* Runtime_KeyedGetProperty(Arguments args) { ...@@ -2604,9 +2604,9 @@ static Object* Runtime_KeyedGetProperty(Arguments args) {
} }
} else { } else {
// Attempt dictionary lookup. // Attempt dictionary lookup.
Dictionary* dictionary = receiver->property_dictionary(); StringDictionary* dictionary = receiver->property_dictionary();
int entry = dictionary->FindStringEntry(key); int entry = dictionary->FindEntry(key);
if ((entry != Dictionary::kNotFound) && if ((entry != StringDictionary::kNotFound) &&
(dictionary->DetailsAt(entry).type() == NORMAL)) { (dictionary->DetailsAt(entry).type() == NORMAL)) {
Object* value = dictionary->ValueAt(entry); Object* value = dictionary->ValueAt(entry);
if (receiver->IsGlobalObject()) { if (receiver->IsGlobalObject()) {
...@@ -5130,8 +5130,8 @@ class ArrayConcatVisitor { ...@@ -5130,8 +5130,8 @@ class ArrayConcatVisitor {
storage_->set(index, *elm); storage_->set(index, *elm);
} else { } else {
Handle<Dictionary> dict = Handle<Dictionary>::cast(storage_); Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
Handle<Dictionary> result = Handle<NumberDictionary> result =
Factory::DictionaryAtNumberPut(dict, index, elm); Factory::DictionaryAtNumberPut(dict, index, elm);
if (!result.is_identical_to(dict)) if (!result.is_identical_to(dict))
storage_ = result; storage_ = result;
...@@ -5179,7 +5179,7 @@ static uint32_t IterateElements(Handle<JSObject> receiver, ...@@ -5179,7 +5179,7 @@ static uint32_t IterateElements(Handle<JSObject> receiver,
} }
} else { } else {
Handle<Dictionary> dict(receiver->element_dictionary()); Handle<NumberDictionary> dict(receiver->element_dictionary());
uint32_t capacity = dict->Capacity(); uint32_t capacity = dict->Capacity();
for (uint32_t j = 0; j < capacity; j++) { for (uint32_t j = 0; j < capacity; j++) {
Handle<Object> k(dict->KeyAt(j)); Handle<Object> k(dict->KeyAt(j));
...@@ -5333,7 +5333,7 @@ static Object* Runtime_ArrayConcat(Arguments args) { ...@@ -5333,7 +5333,7 @@ static Object* Runtime_ArrayConcat(Arguments args) {
uint32_t at_least_space_for = estimate_nof_elements + uint32_t at_least_space_for = estimate_nof_elements +
(estimate_nof_elements >> 2); (estimate_nof_elements >> 2);
storage = Handle<FixedArray>::cast( storage = Handle<FixedArray>::cast(
Factory::NewDictionary(at_least_space_for)); Factory::NewNumberDictionary(at_least_space_for));
} }
Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
...@@ -5396,7 +5396,7 @@ static Object* Runtime_EstimateNumberOfElements(Arguments args) { ...@@ -5396,7 +5396,7 @@ static Object* Runtime_EstimateNumberOfElements(Arguments args) {
CONVERT_CHECKED(JSArray, array, args[0]); CONVERT_CHECKED(JSArray, array, args[0]);
HeapObject* elements = array->elements(); HeapObject* elements = array->elements();
if (elements->IsDictionary()) { if (elements->IsDictionary()) {
return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements()); return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
} else { } else {
return array->length(); return array->length();
} }
......
...@@ -562,8 +562,8 @@ Object* StubCache::ComputeCallGlobal(int argc, ...@@ -562,8 +562,8 @@ Object* StubCache::ComputeCallGlobal(int argc,
static Object* GetProbeValue(Code::Flags flags) { static Object* GetProbeValue(Code::Flags flags) {
Dictionary* dictionary = Heap::non_monomorphic_cache(); NumberDictionary* dictionary = Heap::non_monomorphic_cache();
int entry = dictionary->FindNumberEntry(flags); int entry = dictionary->FindEntry(flags);
if (entry != -1) return dictionary->ValueAt(entry); if (entry != -1) return dictionary->ValueAt(entry);
return Heap::undefined_value(); return Heap::undefined_value();
} }
...@@ -579,7 +579,7 @@ static Object* ProbeCache(Code::Flags flags) { ...@@ -579,7 +579,7 @@ static Object* ProbeCache(Code::Flags flags) {
Heap::non_monomorphic_cache()->AtNumberPut(flags, Heap::non_monomorphic_cache()->AtNumberPut(flags,
Heap::undefined_value()); Heap::undefined_value());
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
Heap::set_non_monomorphic_cache(Dictionary::cast(result)); Heap::set_non_monomorphic_cache(NumberDictionary::cast(result));
return probe; return probe;
} }
...@@ -587,7 +587,7 @@ static Object* ProbeCache(Code::Flags flags) { ...@@ -587,7 +587,7 @@ static Object* ProbeCache(Code::Flags flags) {
static Object* FillCache(Object* code) { static Object* FillCache(Object* code) {
if (code->IsCode()) { if (code->IsCode()) {
int entry = int entry =
Heap::non_monomorphic_cache()->FindNumberEntry( Heap::non_monomorphic_cache()->FindEntry(
Code::cast(code)->flags()); Code::cast(code)->flags());
// The entry must be present see comment in ProbeCache. // The entry must be present see comment in ProbeCache.
ASSERT(entry != -1); ASSERT(entry != -1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment