| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_OBJECTS_H_ | 5 #ifndef V8_OBJECTS_H_ |
| 6 #define V8_OBJECTS_H_ | 6 #define V8_OBJECTS_H_ |
| 7 | 7 |
| 8 #include "allocation.h" | 8 #include "allocation.h" |
| 9 #include "assert-scope.h" | 9 #include "assert-scope.h" |
| 10 #include "builtins.h" | 10 #include "builtins.h" |
| (...skipping 4135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4146 // equality operator and Object::GetHash() for the hash function. | 4146 // equality operator and Object::GetHash() for the hash function. |
| 4147 // | 4147 // |
| 4148 // Based on the "Deterministic Hash Table" as described by Jason Orendorff at | 4148 // Based on the "Deterministic Hash Table" as described by Jason Orendorff at |
| 4149 // https://wiki.mozilla.org/User:Jorend/Deterministic_hash_tables | 4149 // https://wiki.mozilla.org/User:Jorend/Deterministic_hash_tables |
| 4150 // Originally attributed to Tyler Close. | 4150 // Originally attributed to Tyler Close. |
| 4151 // | 4151 // |
| 4152 // Memory layout: | 4152 // Memory layout: |
| 4153 // [0]: bucket count | 4153 // [0]: bucket count |
| 4154 // [1]: element count | 4154 // [1]: element count |
| 4155 // [2]: deleted element count | 4155 // [2]: deleted element count |
| 4156 // [3]: live iterators (doubly-linked list) | 4156 // [3..(3 + NumberOfBuckets() - 1)]: "hash table", where each item is an |
| 4157 // [4..(NumberOfBuckets() - 1)]: "hash table", where each item is an offset | 4157 // offset into the data table (see below) where the |
| 4158 // into the data table (see below) where the | 4158 // first item in this bucket is stored. |
| 4159 // first item in this bucket is stored. | 4159 // [3 + NumberOfBuckets()..length]: "data table", an array of length |
| 4160 // [4 + NumberOfBuckets()..length]: "data table", an array of length | |
| 4161 // Capacity() * kEntrySize, where the first entrysize | 4160 // Capacity() * kEntrySize, where the first entrysize |
| 4162 // items are handled by the derived class and the | 4161 // items are handled by the derived class and the |
| 4163 // item at kChainOffset is another entry into the | 4162 // item at kChainOffset is another entry into the |
| 4164 // data table indicating the next entry in this hash | 4163 // data table indicating the next entry in this hash |
| 4165 // bucket. | 4164 // bucket. |
| 4165 // |
| 4166 // When we transition the table to a new version we obsolete it and reuse parts |
| 4167 // of the memory to store information how to transition an iterator to the new |
| 4168 // table: |
| 4169 // |
| 4170 // Memory layout for obsolete table: |
| 4171 // [0]: bucket count |
| 4172 // [1]: Next newer table |
| 4173 // [2]: Number of removed holes or -1 when the table was cleared. |
| 4174 // [3..(3 + NumberOfRemovedHoles() - 1)]: The indexes of the removed holes. |
| 4175 // [3 + NumberOfRemovedHoles()..length]: Not used |
| 4176 // |
| 4166 template<class Derived, class Iterator, int entrysize> | 4177 template<class Derived, class Iterator, int entrysize> |
| 4167 class OrderedHashTable: public FixedArray { | 4178 class OrderedHashTable: public FixedArray { |
| 4168 public: | 4179 public: |
| 4169 // Returns an OrderedHashTable with a capacity of at least |capacity|. | 4180 // Returns an OrderedHashTable with a capacity of at least |capacity|. |
| 4170 static Handle<Derived> Allocate( | 4181 static Handle<Derived> Allocate( |
| 4171 Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED); | 4182 Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED); |
| 4172 | 4183 |
| 4173 // Returns an OrderedHashTable (possibly |table|) with enough space | 4184 // Returns an OrderedHashTable (possibly |table|) with enough space |
| 4174 // to add at least one new element. | 4185 // to add at least one new element. |
| 4175 static Handle<Derived> EnsureGrowable(Handle<Derived> table); | 4186 static Handle<Derived> EnsureGrowable(Handle<Derived> table); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4192 int NumberOfDeletedElements() { | 4203 int NumberOfDeletedElements() { |
| 4193 return Smi::cast(get(kNumberOfDeletedElementsIndex))->value(); | 4204 return Smi::cast(get(kNumberOfDeletedElementsIndex))->value(); |
| 4194 } | 4205 } |
| 4195 | 4206 |
| 4196 int UsedCapacity() { return NumberOfElements() + NumberOfDeletedElements(); } | 4207 int UsedCapacity() { return NumberOfElements() + NumberOfDeletedElements(); } |
| 4197 | 4208 |
| 4198 int NumberOfBuckets() { | 4209 int NumberOfBuckets() { |
| 4199 return Smi::cast(get(kNumberOfBucketsIndex))->value(); | 4210 return Smi::cast(get(kNumberOfBucketsIndex))->value(); |
| 4200 } | 4211 } |
| 4201 | 4212 |
| 4202 Object* iterators() { return get(kIteratorsIndex); } | |
| 4203 | |
| 4204 void set_iterators(Object* value) { set(kIteratorsIndex, value); } | |
| 4205 | |
| 4206 // Returns the index into the data table where the new entry | 4213 // Returns the index into the data table where the new entry |
| 4207 // should be placed. The table is assumed to have enough space | 4214 // should be placed. The table is assumed to have enough space |
| 4208 // for a new entry. | 4215 // for a new entry. |
| 4209 int AddEntry(int hash); | 4216 int AddEntry(int hash); |
| 4210 | 4217 |
| 4211 // Removes the entry, and puts the_hole in entrysize pointers | 4218 // Removes the entry, and puts the_hole in entrysize pointers |
| 4212 // (leaving the hash table chain intact). | 4219 // (leaving the hash table chain intact). |
| 4213 void RemoveEntry(int entry); | 4220 void RemoveEntry(int entry); |
| 4214 | 4221 |
| 4215 // Returns an index into |this| for the given entry. | 4222 // Returns an index into |this| for the given entry. |
| 4216 int EntryToIndex(int entry) { | 4223 int EntryToIndex(int entry) { |
| 4217 return kHashTableStartIndex + NumberOfBuckets() + (entry * kEntrySize); | 4224 return kHashTableStartIndex + NumberOfBuckets() + (entry * kEntrySize); |
| 4218 } | 4225 } |
| 4219 | 4226 |
| 4220 Object* KeyAt(int entry) { return get(EntryToIndex(entry)); } | 4227 Object* KeyAt(int entry) { return get(EntryToIndex(entry)); } |
| 4221 | 4228 |
| 4229 bool IsObsolete() { |
| 4230 return !get(kNextTableIndex)->IsSmi(); |
| 4231 } |
| 4232 |
| 4233 // The next newer table. This is only valid if the table is obsolete. |
| 4234 Derived* NextTable() { |
| 4235 return Derived::cast(get(kNextTableIndex)); |
| 4236 } |
| 4237 |
| 4238 // When the table is obsolete we store the indexes of the removed holes. |
| 4239 int RemovedIndexAt(int index) { |
| 4240 return Smi::cast(get(kRemovedHolesIndex + index))->value(); |
| 4241 } |
| 4242 |
| 4222 static const int kNotFound = -1; | 4243 static const int kNotFound = -1; |
| 4223 static const int kMinCapacity = 4; | 4244 static const int kMinCapacity = 4; |
| 4224 | 4245 |
| 4225 private: | 4246 private: |
| 4226 static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity); | 4247 static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity); |
| 4227 | 4248 |
| 4228 void SetNumberOfBuckets(int num) { | 4249 void SetNumberOfBuckets(int num) { |
| 4229 set(kNumberOfBucketsIndex, Smi::FromInt(num)); | 4250 set(kNumberOfBucketsIndex, Smi::FromInt(num)); |
| 4230 } | 4251 } |
| 4231 | 4252 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4248 | 4269 |
| 4249 int HashToBucket(int hash) { | 4270 int HashToBucket(int hash) { |
| 4250 return hash & (NumberOfBuckets() - 1); | 4271 return hash & (NumberOfBuckets() - 1); |
| 4251 } | 4272 } |
| 4252 | 4273 |
| 4253 int HashToEntry(int hash) { | 4274 int HashToEntry(int hash) { |
| 4254 int bucket = HashToBucket(hash); | 4275 int bucket = HashToBucket(hash); |
| 4255 return Smi::cast(get(kHashTableStartIndex + bucket))->value(); | 4276 return Smi::cast(get(kHashTableStartIndex + bucket))->value(); |
| 4256 } | 4277 } |
| 4257 | 4278 |
| 4279 void SetNextTable(Derived* next_table) { |
| 4280 set(kNextTableIndex, next_table); |
| 4281 } |
| 4282 |
| 4283 void SetRemovedIndexAt(int index, int removed_index) { |
| 4284 return set(kRemovedHolesIndex + index, Smi::FromInt(removed_index)); |
| 4285 } |
| 4286 |
| 4258 static const int kNumberOfBucketsIndex = 0; | 4287 static const int kNumberOfBucketsIndex = 0; |
| 4259 static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1; | 4288 static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1; |
| 4260 static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1; | 4289 static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1; |
| 4261 static const int kIteratorsIndex = kNumberOfDeletedElementsIndex + 1; | 4290 static const int kHashTableStartIndex = kNumberOfDeletedElementsIndex + 1; |
| 4262 static const int kHashTableStartIndex = kIteratorsIndex + 1; | 4291 |
| 4292 static const int kNextTableIndex = kNumberOfElementsIndex; |
| 4293 static const int kRemovedHolesIndex = kHashTableStartIndex; |
| 4263 | 4294 |
| 4264 static const int kEntrySize = entrysize + 1; | 4295 static const int kEntrySize = entrysize + 1; |
| 4265 static const int kChainOffset = entrysize; | 4296 static const int kChainOffset = entrysize; |
| 4266 | 4297 |
| 4267 static const int kLoadFactor = 2; | 4298 static const int kLoadFactor = 2; |
| 4268 static const int kMaxCapacity = | 4299 static const int kMaxCapacity = |
| 4269 (FixedArray::kMaxLength - kHashTableStartIndex) | 4300 (FixedArray::kMaxLength - kHashTableStartIndex) |
| 4270 / (1 + (kEntrySize * kLoadFactor)); | 4301 / (1 + (kEntrySize * kLoadFactor)); |
| 4271 }; | 4302 }; |
| 4272 | 4303 |
| (...skipping 5676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9949 static const int kSize = kTableOffset + kPointerSize; | 9980 static const int kSize = kTableOffset + kPointerSize; |
| 9950 | 9981 |
| 9951 private: | 9982 private: |
| 9952 DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap); | 9983 DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap); |
| 9953 }; | 9984 }; |
| 9954 | 9985 |
| 9955 | 9986 |
| 9956 // OrderedHashTableIterator is an iterator that iterates over the keys and | 9987 // OrderedHashTableIterator is an iterator that iterates over the keys and |
| 9957 // values of an OrderedHashTable. | 9988 // values of an OrderedHashTable. |
| 9958 // | 9989 // |
| 9959 // The hash table has a reference to the iterator and the iterators themselves | 9990 // The iterator has a reference to the underlying OrderedHashTable data, |
| 9960 // have references to the [next_iterator] and [previous_iterator], thus creating | 9991 // [table], as well as the current [index] the iterator is at. |
| 9961 // a double linked list. | |
| 9962 // | 9992 // |
| 9963 // When the hash table changes the iterators are called to update their [index] | 9993 // When the OrderedHashTable is rehashed it adds a reference from the old table |
| 9964 // and [count]. The hash table calls [EntryRemoved], [TableCompacted] as well | 9994 // to the new table as well as storing enough data about the changes so that the |
| 9965 // as [TableCleared]. | 9995 // iterator [index] can be adjusted accordingly. |
| 9966 // | 9996 // |
| 9967 // When an iterator is done it closes itself. It removes itself from the double | 9997 // When the [Next] result from the iterator is requested, the iterator checks if |
| 9968 // linked list and it sets its [table] to undefined, no longer keeping the | 9998 // there is a newer table that it needs to transition to. |
| 9969 // [table] alive. | |
| 9970 template<class Derived, class TableType> | 9999 template<class Derived, class TableType> |
| 9971 class OrderedHashTableIterator: public JSObject { | 10000 class OrderedHashTableIterator: public JSObject { |
| 9972 public: | 10001 public: |
| 9973 // [table]: the backing hash table mapping keys to values. | 10002 // [table]: the backing hash table mapping keys to values. |
| 9974 DECL_ACCESSORS(table, Object) | 10003 DECL_ACCESSORS(table, Object) |
| 9975 | 10004 |
| 9976 // [index]: The index into the data table. | 10005 // [index]: The index into the data table. |
| 9977 DECL_ACCESSORS(index, Smi) | 10006 DECL_ACCESSORS(index, Smi) |
| 9978 | 10007 |
| 9979 // [count]: The logical index into the data table, ignoring the holes. | |
| 9980 DECL_ACCESSORS(count, Smi) | |
| 9981 | |
| 9982 // [kind]: The kind of iteration this is. One of the [Kind] enum values. | 10008 // [kind]: The kind of iteration this is. One of the [Kind] enum values. |
| 9983 DECL_ACCESSORS(kind, Smi) | 10009 DECL_ACCESSORS(kind, Smi) |
| 9984 | 10010 |
| 9985 // [next_iterator]: Used as a double linked list for the live iterators. | |
| 9986 DECL_ACCESSORS(next_iterator, Object) | |
| 9987 | |
| 9988 // [previous_iterator]: Used as a double linked list for the live iterators. | |
| 9989 DECL_ACCESSORS(previous_iterator, Object) | |
| 9990 | |
| 9991 #ifdef OBJECT_PRINT | 10011 #ifdef OBJECT_PRINT |
| 9992 void OrderedHashTableIteratorPrint(FILE* out); | 10012 void OrderedHashTableIteratorPrint(FILE* out); |
| 9993 #endif | 10013 #endif |
| 9994 | 10014 |
| 9995 static const int kTableOffset = JSObject::kHeaderSize; | 10015 static const int kTableOffset = JSObject::kHeaderSize; |
| 9996 static const int kIndexOffset = kTableOffset + kPointerSize; | 10016 static const int kIndexOffset = kTableOffset + kPointerSize; |
| 9997 static const int kCountOffset = kIndexOffset + kPointerSize; | 10017 static const int kKindOffset = kIndexOffset + kPointerSize; |
| 9998 static const int kKindOffset = kCountOffset + kPointerSize; | 10018 static const int kSize = kKindOffset + kPointerSize; |
| 9999 static const int kNextIteratorOffset = kKindOffset + kPointerSize; | |
| 10000 static const int kPreviousIteratorOffset = kNextIteratorOffset + kPointerSize; | |
| 10001 static const int kSize = kPreviousIteratorOffset + kPointerSize; | |
| 10002 | 10019 |
| 10003 enum Kind { | 10020 enum Kind { |
| 10004 kKindKeys = 1, | 10021 kKindKeys = 1, |
| 10005 kKindValues = 2, | 10022 kKindValues = 2, |
| 10006 kKindEntries = 3 | 10023 kKindEntries = 3 |
| 10007 }; | 10024 }; |
| 10008 | 10025 |
| 10009 // Called by the underlying [table] when an entry is removed. | |
| 10010 void EntryRemoved(int index); | |
| 10011 | |
| 10012 // Called by the underlying [table] when it is compacted/rehashed. | |
| 10013 void TableCompacted() { | |
| 10014 // All holes have been removed so index is now same as count. | |
| 10015 set_index(count()); | |
| 10016 } | |
| 10017 | |
| 10018 // Called by the underlying [table] when it is cleared. | |
| 10019 void TableCleared() { | |
| 10020 set_index(Smi::FromInt(0)); | |
| 10021 set_count(Smi::FromInt(0)); | |
| 10022 } | |
| 10023 | |
| 10024 // Removes the iterator from the double linked list and removes its reference | |
| 10025 // back to the [table]. | |
| 10026 void Close(); | |
| 10027 | |
| 10028 // Returns an iterator result object: {value: any, done: boolean} and moves | 10026 // Returns an iterator result object: {value: any, done: boolean} and moves |
| 10029 // the index to the next valid entry. Closes the iterator if moving past the | 10027 // the index to the next valid entry. Closes the iterator if moving past the |
| 10030 // end. | 10028 // end. |
| 10031 static Handle<JSObject> Next(Handle<Derived> iterator); | 10029 static Handle<JSObject> Next(Handle<Derived> iterator); |
| 10032 | 10030 |
| 10033 protected: | 10031 protected: |
| 10034 static Handle<Derived> CreateInternal( | 10032 static Handle<Derived> CreateInternal( |
| 10035 Handle<Map> map, Handle<TableType> table, int kind); | 10033 Handle<Map> map, Handle<TableType> table, int kind); |
| 10036 | 10034 |
| 10037 private: | 10035 private: |
| 10038 // Ensures [index] is not pointing to a hole. | 10036 // Transitions the iterator to the non obsolote backing store. This is a NOP |
| 10039 void Seek(); | 10037 // if the [table] is not obsolete. |
| 10040 | 10038 void Transition(); |
| 10041 // Moves [index] to next valid entry. Closes the iterator if moving past the | |
| 10042 // end. | |
| 10043 void MoveNext(); | |
| 10044 | |
| 10045 bool Closed() { | |
| 10046 return table()->IsUndefined(); | |
| 10047 } | |
| 10048 | 10039 |
| 10049 DISALLOW_IMPLICIT_CONSTRUCTORS(OrderedHashTableIterator); | 10040 DISALLOW_IMPLICIT_CONSTRUCTORS(OrderedHashTableIterator); |
| 10050 }; | 10041 }; |
| 10051 | 10042 |
| 10052 | 10043 |
| 10053 class JSSetIterator: public OrderedHashTableIterator<JSSetIterator, | 10044 class JSSetIterator: public OrderedHashTableIterator<JSSetIterator, |
| 10054 OrderedHashSet> { | 10045 OrderedHashSet> { |
| 10055 public: | 10046 public: |
| 10056 // Creates a new iterator associated with [table]. | 10047 // Creates a new iterator associated with [table]. |
| 10057 // [kind] needs to be one of the OrderedHashTableIterator Kind enum values. | 10048 // [kind] needs to be one of the OrderedHashTableIterator Kind enum values. |
| 10058 static inline Handle<JSSetIterator> Create( | 10049 static inline Handle<JSSetIterator> Create( |
| 10059 Handle<OrderedHashSet> table, int kind); | 10050 Handle<OrderedHashSet> table, int kind); |
| 10060 | 10051 |
| 10061 // Dispatched behavior. | 10052 // Dispatched behavior. |
| 10062 DECLARE_PRINTER(JSSetIterator) | 10053 DECLARE_PRINTER(JSSetIterator) |
| 10063 DECLARE_VERIFIER(JSSetIterator) | 10054 DECLARE_VERIFIER(JSSetIterator) |
| 10064 | 10055 |
| 10065 // Casting. | 10056 // Casting. |
| 10066 static inline JSSetIterator* cast(Object* obj); | 10057 static inline JSSetIterator* cast(Object* obj); |
| 10067 | 10058 |
| 10068 static Handle<Object> ValueForKind( | 10059 static Handle<Object> ValueForKind( |
| 10069 Handle<JSSetIterator> iterator, int entry_index); | 10060 Handle<JSSetIterator> iterator, |
| 10061 int entry_index); |
| 10070 | 10062 |
| 10071 private: | 10063 private: |
| 10072 DISALLOW_IMPLICIT_CONSTRUCTORS(JSSetIterator); | 10064 DISALLOW_IMPLICIT_CONSTRUCTORS(JSSetIterator); |
| 10073 }; | 10065 }; |
| 10074 | 10066 |
| 10075 | 10067 |
| 10076 class JSMapIterator: public OrderedHashTableIterator<JSMapIterator, | 10068 class JSMapIterator: public OrderedHashTableIterator<JSMapIterator, |
| 10077 OrderedHashMap> { | 10069 OrderedHashMap> { |
| 10078 public: | 10070 public: |
| 10079 // Creates a new iterator associated with [table]. | 10071 // Creates a new iterator associated with [table]. |
| 10080 // [kind] needs to be one of the OrderedHashTableIterator Kind enum values. | 10072 // [kind] needs to be one of the OrderedHashTableIterator Kind enum values. |
| 10081 static inline Handle<JSMapIterator> Create( | 10073 static inline Handle<JSMapIterator> Create( |
| 10082 Handle<OrderedHashMap> table, int kind); | 10074 Handle<OrderedHashMap> table, int kind); |
| 10083 | 10075 |
| 10084 // Dispatched behavior. | 10076 // Dispatched behavior. |
| 10085 DECLARE_PRINTER(JSMapIterator) | 10077 DECLARE_PRINTER(JSMapIterator) |
| 10086 DECLARE_VERIFIER(JSMapIterator) | 10078 DECLARE_VERIFIER(JSMapIterator) |
| 10087 | 10079 |
| 10088 // Casting. | 10080 // Casting. |
| 10089 static inline JSMapIterator* cast(Object* obj); | 10081 static inline JSMapIterator* cast(Object* obj); |
| 10090 | 10082 |
| 10091 static Handle<Object> ValueForKind( | 10083 static Handle<Object> ValueForKind( |
| 10092 Handle<JSMapIterator> iterator, int entry_index); | 10084 Handle<JSMapIterator> iterator, |
| 10085 int entry_index); |
| 10093 | 10086 |
| 10094 private: | 10087 private: |
| 10095 DISALLOW_IMPLICIT_CONSTRUCTORS(JSMapIterator); | 10088 DISALLOW_IMPLICIT_CONSTRUCTORS(JSMapIterator); |
| 10096 }; | 10089 }; |
| 10097 | 10090 |
| 10098 | 10091 |
| 10099 // Base class for both JSWeakMap and JSWeakSet | 10092 // Base class for both JSWeakMap and JSWeakSet |
| 10100 class JSWeakCollection: public JSObject { | 10093 class JSWeakCollection: public JSObject { |
| 10101 public: | 10094 public: |
| 10102 // [table]: the backing hash table mapping keys to values. | 10095 // [table]: the backing hash table mapping keys to values. |
| (...skipping 1014 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11117 } else { | 11110 } else { |
| 11118 value &= ~(1 << bit_position); | 11111 value &= ~(1 << bit_position); |
| 11119 } | 11112 } |
| 11120 return value; | 11113 return value; |
| 11121 } | 11114 } |
| 11122 }; | 11115 }; |
| 11123 | 11116 |
| 11124 } } // namespace v8::internal | 11117 } } // namespace v8::internal |
| 11125 | 11118 |
| 11126 #endif // V8_OBJECTS_H_ | 11119 #endif // V8_OBJECTS_H_ |
| OLD | NEW |