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
This commit is contained in:
parent
9518261f2b
commit
5cbb209425
@ -1434,8 +1434,8 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Handle<Dictionary> properties =
|
||||
Handle<Dictionary>(from->property_dictionary());
|
||||
Handle<StringDictionary> properties =
|
||||
Handle<StringDictionary>(from->property_dictionary());
|
||||
int capacity = properties->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* raw_key(properties->KeyAt(i));
|
||||
|
@ -37,8 +37,8 @@ namespace internal {
|
||||
|
||||
Handle<Code> 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<Code> CodeStub::GetCode() {
|
||||
#endif
|
||||
|
||||
// Update the dictionary and the root in Heap.
|
||||
Handle<Dictionary> dict =
|
||||
Factory::DictionaryAtNumberPut(Handle<Dictionary>(Heap::code_stubs()),
|
||||
key,
|
||||
code);
|
||||
Handle<NumberDictionary> dict =
|
||||
Factory::DictionaryAtNumberPut(
|
||||
Handle<NumberDictionary>(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>(Code::cast(Heap::code_stubs()->ValueAt(index)));
|
||||
}
|
||||
|
@ -49,9 +49,17 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Dictionary> Factory::NewDictionary(int at_least_space_for) {
|
||||
Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) {
|
||||
ASSERT(0 <= at_least_space_for);
|
||||
CALL_HEAP_FUNCTION(Dictionary::Allocate(at_least_space_for), Dictionary);
|
||||
CALL_HEAP_FUNCTION(StringDictionary::Allocate(at_least_space_for),
|
||||
StringDictionary);
|
||||
}
|
||||
|
||||
|
||||
Handle<NumberDictionary> Factory::NewNumberDictionary(int at_least_space_for) {
|
||||
ASSERT(0 <= at_least_space_for);
|
||||
CALL_HEAP_FUNCTION(NumberDictionary::Allocate(at_least_space_for),
|
||||
NumberDictionary);
|
||||
}
|
||||
|
||||
|
||||
@ -655,10 +663,11 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Dictionary> Factory::DictionaryAtNumberPut(Handle<Dictionary> dictionary,
|
||||
uint32_t key,
|
||||
Handle<Object> value) {
|
||||
CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), Dictionary);
|
||||
Handle<NumberDictionary> Factory::DictionaryAtNumberPut(
|
||||
Handle<NumberDictionary> dictionary,
|
||||
uint32_t key,
|
||||
Handle<Object> value) {
|
||||
CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), NumberDictionary);
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +47,9 @@ class Factory : public AllStatic {
|
||||
// Allocate a new fixed array with non-existing entries (the hole).
|
||||
static Handle<FixedArray> NewFixedArrayWithHoles(int size);
|
||||
|
||||
static Handle<Dictionary> NewDictionary(int at_least_space_for);
|
||||
static Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for);
|
||||
|
||||
static Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
|
||||
|
||||
static Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
|
||||
|
||||
@ -313,9 +315,10 @@ class Factory : public AllStatic {
|
||||
|
||||
static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
|
||||
|
||||
static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>,
|
||||
uint32_t key,
|
||||
Handle<Object> value);
|
||||
static Handle<NumberDictionary> DictionaryAtNumberPut(
|
||||
Handle<NumberDictionary>,
|
||||
uint32_t key,
|
||||
Handle<Object> value);
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
static Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
|
||||
|
@ -198,7 +198,8 @@ class FixedArray;
|
||||
class FunctionEntry;
|
||||
class FunctionLiteral;
|
||||
class FunctionTemplateInfo;
|
||||
class Dictionary;
|
||||
class NumberDictionary;
|
||||
class StringDictionary;
|
||||
class FreeStoreAllocationPolicy;
|
||||
template <typename T> class Handle;
|
||||
class Heap;
|
||||
|
10
src/heap.cc
10
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<Array*>(result)->set_map(hash_table_map());
|
||||
ASSERT(result->IsDictionary());
|
||||
ASSERT(result->IsHashTable());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -744,12 +744,12 @@ void Proxy::ProxyVerify() {
|
||||
ASSERT(IsProxy());
|
||||
}
|
||||
|
||||
|
||||
void Dictionary::Print() {
|
||||
int capacity = Capacity();
|
||||
template<typename Shape, typename Key>
|
||||
void Dictionary<Shape, Key>::Print() {
|
||||
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 (HashTable<Shape, Key>::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();
|
||||
|
@ -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 <int prefix_size, int elem_size>
|
||||
HashTable<prefix_size, elem_size>* HashTable<prefix_size, elem_size>::cast(
|
||||
Object* obj) {
|
||||
|
||||
template <typename Shape, typename Key>
|
||||
HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
|
||||
ASSERT(obj->IsHashTable());
|
||||
return reinterpret_cast<HashTable*>(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<typename Shape, typename Key>
|
||||
void Dictionary<Shape, Key>::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<Shape, Key>::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());
|
||||
}
|
||||
|
||||
|
||||
|
591
src/objects.cc
591
src/objects.cc
File diff suppressed because it is too large
Load Diff
357
src/objects.h
357
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<int prefix_size, int element_size>
|
||||
template<typename Shape, typename Key>
|
||||
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<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
|
||||
@ -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<MapCacheShape, HashTableKey*> {
|
||||
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 <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);
|
||||
@ -2117,14 +2142,113 @@ 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);
|
||||
|
||||
// Accessors for next enumeration index.
|
||||
void SetNextEnumerationIndex(int index) {
|
||||
fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index));
|
||||
}
|
||||
|
||||
int NextEnumerationIndex() {
|
||||
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, Key key);
|
||||
|
||||
#ifdef DEBUG
|
||||
void Print();
|
||||
#endif
|
||||
// Returns the key (slow).
|
||||
Object* SlowReverseLookup(Object* value);
|
||||
|
||||
// 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 =
|
||||
HashTable<Shape, Key>::kPrefixStartIndex;
|
||||
static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
|
||||
};
|
||||
|
||||
|
||||
class StringDictionaryShape {
|
||||
public:
|
||||
static inline bool IsMatch(String* key, Object* other);
|
||||
static inline uint32_t Hash(String* key);
|
||||
static inline uint32_t HashForObject(String* key, Object* object);
|
||||
static inline Object* AsObject(String* key);
|
||||
static const int kPrefixSize = 2;
|
||||
static const int kEntrySize = 3;
|
||||
static const bool kIsEnumerable = true;
|
||||
};
|
||||
|
||||
|
||||
class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
|
||||
public:
|
||||
static inline StringDictionary* cast(Object* obj) {
|
||||
ASSERT(obj->IsDictionary());
|
||||
return reinterpret_cast<StringDictionary*>(obj);
|
||||
}
|
||||
|
||||
// Copies enumerable keys to preallocated fixed array.
|
||||
void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array);
|
||||
|
||||
// For transforming properties of a JSObject.
|
||||
Object* TransformPropertiesToFastFor(JSObject* obj,
|
||||
int unused_property_fields);
|
||||
};
|
||||
|
||||
|
||||
class NumberDictionaryShape {
|
||||
public:
|
||||
static inline bool IsMatch(uint32_t key, Object* other);
|
||||
static inline uint32_t Hash(uint32_t key);
|
||||
static inline uint32_t HashForObject(uint32_t key, Object* object);
|
||||
static inline Object* AsObject(uint32_t key);
|
||||
static const int kPrefixSize = 2;
|
||||
static const int kEntrySize = 3;
|
||||
static const bool kIsEnumerable = false;
|
||||
};
|
||||
|
||||
|
||||
class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
|
||||
public:
|
||||
static NumberDictionary* cast(Object* obj) {
|
||||
ASSERT(obj->IsDictionary());
|
||||
return reinterpret_cast<NumberDictionary*>(obj);
|
||||
}
|
||||
|
||||
// Type specific at put (default NONE attributes is used when adding).
|
||||
Object* AtNumberPut(uint32_t key, Object* value);
|
||||
Object* AddNumberEntry(uint32_t key,
|
||||
Object* value,
|
||||
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
|
||||
@ -2139,59 +2263,13 @@ class Dictionary: public DictionaryBase {
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
#ifdef DEBUG
|
||||
void Print();
|
||||
#endif
|
||||
// Returns the key (slow).
|
||||
Object* SlowReverseLookup(Object* value);
|
||||
// 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;
|
||||
|
||||
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);
|
||||
|
||||
// Generate new enumeration indices to avoid enumeration index overflow.
|
||||
Object* GenerateNewEnumerationIndices();
|
||||
|
||||
static const int kMaxNumberKeyIndex = kPrefixStartIndex;
|
||||
static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary);
|
||||
};
|
||||
|
||||
|
||||
@ -3231,7 +3309,30 @@ class JSRegExp: public JSObject {
|
||||
};
|
||||
|
||||
|
||||
class CompilationCacheTable: public HashTable<0, 2> {
|
||||
class CompilationCacheShape {
|
||||
public:
|
||||
static inline bool IsMatch(HashTableKey* key, Object* value) {
|
||||
return key->IsMatch(value);
|
||||
}
|
||||
|
||||
static inline uint32_t Hash(HashTableKey* key) {
|
||||
return key->Hash();
|
||||
}
|
||||
|
||||
static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
|
||||
return key->HashForObject(object);
|
||||
}
|
||||
|
||||
static Object* AsObject(HashTableKey* key) {
|
||||
return key->AsObject();
|
||||
}
|
||||
|
||||
static const int kPrefixSize = 0;
|
||||
static const int kEntrySize = 2;
|
||||
};
|
||||
|
||||
class CompilationCacheTable: public HashTable<CompilationCacheShape,
|
||||
HashTableKey*> {
|
||||
public:
|
||||
// Find cached value for a string key, otherwise return null.
|
||||
Object* Lookup(String* src);
|
||||
|
@ -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<Dictionary> dict = Handle<Dictionary>::cast(storage_);
|
||||
Handle<Dictionary> result =
|
||||
Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
|
||||
Handle<NumberDictionary> result =
|
||||
Factory::DictionaryAtNumberPut(dict, index, elm);
|
||||
if (!result.is_identical_to(dict))
|
||||
storage_ = result;
|
||||
@ -5179,7 +5179,7 @@ static uint32_t IterateElements(Handle<JSObject> receiver,
|
||||
}
|
||||
|
||||
} else {
|
||||
Handle<Dictionary> dict(receiver->element_dictionary());
|
||||
Handle<NumberDictionary> dict(receiver->element_dictionary());
|
||||
uint32_t capacity = dict->Capacity();
|
||||
for (uint32_t j = 0; j < capacity; j++) {
|
||||
Handle<Object> 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<FixedArray>::cast(
|
||||
Factory::NewDictionary(at_least_space_for));
|
||||
Factory::NewNumberDictionary(at_least_space_for));
|
||||
}
|
||||
|
||||
Handle<Object> len = Factory::NewNumber(static_cast<double>(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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user