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