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 |