#include "disassembler.h"
#endif
+
namespace v8 {
namespace internal {
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.
// 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;
}
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);
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);
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;
}
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.
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) {
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);
// 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();
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: {
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: {
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:
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);
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.
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();
}
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);
}
}
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();
// 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);
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) {
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.
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()) {
return true;
}
} else {
- if (element_dictionary()->FindNumberEntry(index) != Dictionary::kNotFound) {
+ if (element_dictionary()->FindEntry(index)
+ != NumberDictionary::kNotFound) {
return true;
}
}
return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole();
} else {
- return element_dictionary()->FindNumberEntry(index)
- != Dictionary::kNotFound;
+ return element_dictionary()->FindEntry(index)
+ != NumberDictionary::kNotFound;
}
}
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;
}
}
// 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) {
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;
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) {
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) {
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();
}
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
length = dictionary->max_number_key();
}
return static_cast<uint32_t>(dictionary->Capacity()) >=
- (length / (2 * Dictionary::kElementSize));
+ (length / (2 * NumberDictionary::kEntrySize));
}
-
-void Dictionary::CopyValuesTo(FixedArray* elements) {
+template<typename Shape, typename Key>
+void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
int pos = 0;
- int capacity = Capacity();
+ int capacity = HashTable<Shape, Key>::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<Shape, Key>::KeyAt(i);
+ if (Dictionary<Shape, Key>::IsKey(k)) {
+ elements->set(pos++, ValueAt(i), mode);
+ }
}
ASSERT(pos == elements->length());
}
return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole();
}
- return element_dictionary()->FindNumberEntry(index)
- != Dictionary::kNotFound;
+ return element_dictionary()->FindEntry(index)
+ != NumberDictionary::kNotFound;
}
}
-// 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<uint32_t>(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<uint32_t>(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<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.
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));
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_;
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();
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);
return pair;
}
- virtual bool IsStringKey() { return false; }
-
private:
String* source_;
SharedFunctionInfo* shared_;
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)));
return string->Hash() + flags->value();
}
- bool IsStringKey() { return false; }
-
String* string_;
Smi* flags_;
};
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(),
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<const char> string_;
uint32_t length_field_;
int chars_; // Caches the number of characters when computing the hash code.
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()) {
return String::cast(obj)->Hash();
}
- bool IsStringKey() { return true; }
-
String* string_;
};
-template<int prefix_size, int element_size>
-void HashTable<prefix_size, element_size>::IteratePrefix(ObjectVisitor* v) {
+template<typename Shape, typename Key>
+void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
IteratePointers(v, 0, kElementsStartOffset);
}
-template<int prefix_size, int element_size>
-void HashTable<prefix_size, element_size>::IterateElements(ObjectVisitor* v) {
+template<typename Shape, typename Key>
+void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
IteratePointers(v,
kElementsStartOffset,
kHeaderSize + length() * kPointerSize);
}
-template<int prefix_size, int element_size>
-Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) {
+template<typename Shape, typename Key>
+Object* HashTable<Shape, Key>::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));
}
+
// Find entry for key otherwise return -1.
-template <int prefix_size, int element_size>
-int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) {
+template<typename Shape, typename Key>
+int HashTable<Shape, Key>::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;
}
}
}
-template<int prefix_size, int element_size>
-Object* HashTable<prefix_size, element_size>::EnsureCapacity(
- int n, HashTableKey* key) {
+template<typename Shape, typename Key>
+Object* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
int capacity = Capacity();
int nof = NumberOfElements() + n;
// Make sure 50% is free
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);
}
}
}
-template<int prefix_size, int element_size>
-uint32_t HashTable<prefix_size, element_size>::FindInsertionEntry(
- Object* key,
- uint32_t hash) {
+template<typename Shape, typename Key>
+uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
uint32_t capacity = Capacity();
uint32_t entry = GetProbe(hash, 0, capacity);
Object* element = KeyAt(entry);
return entry;
}
+// Force instantiation of template instances class
+template class HashTable<SymbolTableShape, HashTableKey*>;
+
+template class HashTable<CompilationCacheShape, HashTableKey*>;
-// Force instantiation of SymbolTable's base class
-template class HashTable<0, 1>;
+template class HashTable<MapCacheShape, HashTableKey*>;
+template class Dictionary<StringDictionaryShape, String*>;
-// Force instantiation of Dictionary's base class
-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
// zero of the elements. The object stays in Dictionary mode.
// 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<uint32_t>(Smi::kMaxValue)) {
// Allocate space for result before we start mutating the object.
}
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;
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);
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
SymbolTable* table = reinterpret_cast<SymbolTable*>(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;
CompilationCacheTable* cache =
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) + 1, value);
cache->ElementAdded();
CompilationCacheTable* cache =
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;
cache->set(EntryToIndex(entry), k);
CompilationCacheTable* cache =
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) + 1, value);
cache->ElementAdded();
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;
return hash;
}
- bool IsStringKey() { return false; }
+ Object* AsObject() { return symbols_; }
private:
FixedArray* symbols_;
if (obj->IsFailure()) return 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) + 1, value);
cache->ElementAdded();
}
-Object* Dictionary::Allocate(int at_least_space_for) {
- Object* obj = DictionaryBase::Allocate(at_least_space_for);
+template<typename Shape, typename Key>
+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.
if (!obj->IsFailure()) {
- Dictionary::cast(obj)->
+ Dictionary<Shape, Key>::cast(obj)->
SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
}
return obj;
}
-Object* Dictionary::GenerateNewEnumerationIndices() {
- int length = NumberOfElements();
+template<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
+ int length = HashTable<Shape, Key>::NumberOfElements();
// Allocate and initialize iteration order array.
Object* obj = Heap::AllocateFixedArray(length);
FixedArray* enumeration_order = FixedArray::cast(obj);
// Fill the enumeration order array with property details.
- int capacity = Capacity();
+ int capacity = HashTable<Shape, Key>::Capacity();
int pos = 0;
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++,
Smi::FromInt(DetailsAt(i).index()),
SKIP_WRITE_BARRIER);
}
// Update the dictionary with new indices.
- capacity = Capacity();
+ capacity = HashTable<Shape, Key>::Capacity();
pos = 0;
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();
PropertyDetails details = DetailsAt(i);
PropertyDetails new_details =
return this;
}
-
-Object* Dictionary::EnsureCapacity(int n, HashTableKey* key) {
+template<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::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<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.
if (from >= to) return;
SetNumberOfElements(NumberOfElements() - removed_entries);
}
-
-Object* Dictionary::DeleteProperty(int entry, JSObject::DeleteMode mode) {
+template<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::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<Shape, Key>::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<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
int entry = FindEntry(key);
// If the entry is present set the value;
- if (entry != kNotFound) {
+ if (entry != Dictionary<Shape, Key>::kNotFound) {
ValueAtPut(entry, value);
return this;
}
// 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<Shape, Key>::cast(obj)->
+ AddEntry(key, value, details, Shape::Hash(key));
}
-Object* Dictionary::Add(HashTableKey* key, Object* value,
- PropertyDetails details) {
+template<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::Add(Key key,
+ Object* value,
+ PropertyDetails details) {
+ // Valdate key is absent.
+ SLOW_ASSERT((FindEntry(key) == Dictionary<Shape, Key>::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<Shape, Key>::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<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::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<Shape, Key>::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<Shape, Key>::KeyAt(entry)->IsNumber()
+ || 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
// been added at a high index.
if (requires_slow_elements()) return;
// 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<typename Shape, typename Key>
+int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
+ PropertyAttributes filter) {
+ int capacity = HashTable<Shape, Key>::Capacity();
int result = 0;
for (int i = 0; i < capacity; i++) {
- Object* k = KeyAt(i);
- if (IsKey(k)) {
+ Object* k = HashTable<Shape, Key>::KeyAt(i);
+ if (HashTable<Shape, Key>::IsKey(k)) {
PropertyAttributes attr = DetailsAt(i).attributes();
if ((attr & filter) == 0) result++;
}
}
-int Dictionary::NumberOfEnumElements() {
+template<typename Shape, typename Key>
+int Dictionary<Shape, Key>::NumberOfEnumElements() {
return NumberOfElementsFilterAttributes(
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());
- int capacity = Capacity();
+ int capacity = HashTable<Shape, Key>::Capacity();
int index = 0;
for (int i = 0; i < capacity; i++) {
- Object* k = KeyAt(i);
- if (IsKey(k)) {
+ Object* k = HashTable<Shape, Key>::KeyAt(i);
+ if (HashTable<Shape, Key>::IsKey(k)) {
PropertyAttributes attr = DetailsAt(i).attributes();
if ((attr & filter) == 0) storage->set(index++, k);
}
}
-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;
}
-void Dictionary::CopyKeysTo(FixedArray* storage) {
+template<typename Shape, typename Key>
+void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
static_cast<PropertyAttributes>(NONE)));
- int capacity = Capacity();
+ int capacity = HashTable<Shape, Key>::Capacity();
int index = 0;
for (int i = 0; i < capacity; i++) {
- Object* k = KeyAt(i);
- if (IsKey(k)) {
+ Object* k = HashTable<Shape, Key>::KeyAt(i);
+ if (HashTable<Shape, Key>::IsKey(k)) {
storage->set(index++, k);
}
}
// Backwards lookup (slow).
-Object* Dictionary::SlowReverseLookup(Object* value) {
- int capacity = Capacity();
+template<typename Shape, typename Key>
+Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
+ int capacity = HashTable<Shape, Key>::Capacity();
for (int i = 0; i < capacity; i++) {
- Object* k = KeyAt(i);
- if (IsKey(k)) {
+ Object* k = HashTable<Shape, Key>::KeyAt(i);
+ if (Dictionary<Shape, Key>::IsKey(k)) {
Object* e = ValueAt(i);
if (e->IsJSGlobalPropertyCell()) {
e = JSGlobalPropertyCell::cast(e)->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;
// 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;
}
#endif
+
} } // namespace v8::internal
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
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.
// - 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<int prefix_size, int element_size>
+template<typename Shape, typename Key>
class HashTable: public FixedArray {
public:
// Returns the number of elements in the dictionary.
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.
}
// 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<SymbolTableShape, HashTableKey*> {
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
};
+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<MapCacheShape, HashTableKey*> {
public:
// Find cached value for a string key, otherwise return null.
Object* Lookup(FixedArray* key);
};
-// 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 <typename Shape, typename Key>
+class Dictionary: public HashTable<Shape, Key> {
public:
+
+ static inline Dictionary<Shape, Key>* cast(Object* obj) {
+ return reinterpret_cast<Dictionary<Shape, Key>*>(obj);
+ }
+
// Returns the value at entry.
Object* ValueAt(int entry) {
- return get(EntryToIndex(entry)+1);
+ return get(HashTable<Shape, Key>::EntryToIndex(entry)+1);
}
// Set the value for entry.
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.
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<Shape, Key>::EntryToIndex(entry) + 2)));
}
// Set the details for entry.
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
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);
// 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();
// 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<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);
- 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<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,
+ 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;
};
};
-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:
// Find cached value for a string key, otherwise return null.
Object* Lookup(String* src);