Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 7422aec4e6603ddbbf52a3295a9fea13e8da9b6b..167a053051706cbac6e261343b6a9dc0a675b22c 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -7566,19 +7566,23 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
| // in |elements_| to deduce the number of keys to take from the |properties_| |
| // set. |
| Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); |
| - int index = 0; |
| - int properties_index = 0; |
| - for (size_t level = 0; level < levelLengths_.size(); level++) { |
| - int num_total = levelLengths_[level]; |
| - int num_elements = 0; |
| - if (num_total < 0) { |
| - // If the total is negative, the current level contains properties from a |
| - // proxy, hence we skip the integer keys in |elements_| since proxies |
| - // define the complete ordering. |
| - num_total = -num_total; |
| + int insertion_index = 0; |
| + int string_properties_index = 0; |
| + int symbol_properties_index = 0; |
| + // String and Symbol lengths always come in pairs: |
| + size_t max_level = level_lengths_.size() / 2; |
| + for (size_t level = 0; level < max_level; level++) { |
| + int num_string_properties = level_lengths_[level * 2]; |
| + int num_symbol_properties = level_lengths_[level * 2 + 1]; |
| + if (num_string_properties < 0) { |
| + // If the num_string_properties is negative, the current level contains |
| + // properties from a proxy, hence we skip the integer keys in |elements_| |
| + // since proxies define the complete ordering. |
| + num_string_properties = -num_string_properties; |
| } else if (level < elements_.size()) { |
| + // Add the element indices for this prototype level. |
| std::vector<uint32_t>* elements = elements_[level]; |
| - num_elements = static_cast<int>(elements->size()); |
| + int num_elements = static_cast<int>(elements->size()); |
| for (int i = 0; i < num_elements; i++) { |
| Handle<Object> key; |
| if (convert == KEEP_NUMBERS) { |
| @@ -7586,25 +7590,34 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
| } else { |
| key = isolate_->factory()->Uint32ToString(elements->at(i)); |
| } |
| - result->set(index, *key); |
| - index++; |
| + result->set(insertion_index, *key); |
| + insertion_index++; |
| } |
| } |
| - // Add the property keys for this prototype level. |
| - int num_properties = num_total - num_elements; |
| - for (int i = 0; i < num_properties; i++) { |
| - Object* key = properties_->KeyAt(properties_index); |
| - result->set(index, key); |
| - index++; |
| - properties_index++; |
| + // Add the string property keys for this prototype level. |
| + for (int i = 0; i < num_string_properties; i++) { |
| + Object* key = string_properties_->KeyAt(string_properties_index); |
| + result->set(insertion_index, key); |
| + insertion_index++; |
| + string_properties_index++; |
| + } |
| + // Add the symbol property keys for this prototype level. |
| + for (int i = 0; i < num_symbol_properties; i++) { |
| + Object* key = symbol_properties_->KeyAt(symbol_properties_index); |
| + result->set(insertion_index, key); |
| + insertion_index++; |
| + symbol_properties_index++; |
| } |
| } |
| - DCHECK_EQ(index, length_); |
| + DCHECK_EQ(insertion_index, length_); |
| return result; |
| } |
| +int KeyAccumulator::GetLength() { return length_; } |
|
Jakob Kummerow
2015/11/03 15:33:37
nit: a simple getter like this should be called ju
|
| + |
| + |
| namespace { |
| bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) { |
| @@ -7617,7 +7630,7 @@ bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) { |
| bool KeyAccumulator::AddKey(uint32_t key) { |
| // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). |
| // We mark proxy-levels with a negative length |
| - DCHECK_LE(0, levelLength_); |
| + DCHECK_LE(0, level_string_length_); |
| // Binary search over all but the last level. The last one might not be |
| // sorted yet. |
| for (size_t i = 1; i < elements_.size(); i++) { |
| @@ -7625,7 +7638,6 @@ bool KeyAccumulator::AddKey(uint32_t key) { |
| } |
| elements_.back()->push_back(key); |
| length_++; |
| - levelLength_++; |
| return true; |
| } |
| @@ -7636,11 +7648,12 @@ bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { |
| bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| - if (filter_ == SKIP_SYMBOLS && key->IsSymbol()) { |
| - return false; |
| + if (key->IsSymbol()) { |
| + if (filter_ == SKIP_SYMBOLS) return false; |
| + return AddSymbolKey(key); |
| } |
| // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). |
| - DCHECK_LE(0, levelLength_); |
| + DCHECK_LE(0, level_string_length_); |
| // In some cases (e.g. proxies) we might get in String-converted ints which |
| // should be added to the elements list instead of the properties. For |
| // proxies we have to convert as well but also respect the original order. |
| @@ -7648,7 +7661,7 @@ bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| if (convert == CONVERT_TO_ARRAY_INDEX || convert == PROXY_MAGIC) { |
| uint32_t index = 0; |
| int prev_length = length_; |
| - int prev_proto = levelLength_; |
| + int prev_proto = level_string_length_; |
| bool was_array_index = false; |
| bool key_was_added = false; |
| if ((key->IsString() && Handle<String>::cast(key)->AsArrayIndex(&index)) || |
| @@ -7665,24 +7678,48 @@ bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| return false; |
| } |
| length_ = prev_length; |
| - levelLength_ = prev_proto; |
| + level_string_length_ = prev_proto; |
| } |
| } |
| - if (properties_.is_null()) { |
| - properties_ = OrderedHashSet::Allocate(isolate_, 16); |
| + return AddStringKey(key, convert); |
| +} |
| + |
| + |
| +bool KeyAccumulator::AddStringKey(Handle<Object> key, |
| + AddKeyConversion convert) { |
| + if (string_properties_.is_null()) { |
| + string_properties_ = OrderedHashSet::Allocate(isolate_, 16); |
| } |
| // TODO(cbruni): remove this conversion once we throw the correct TypeError |
| // for non-string/symbol elements returned by proxies |
| if (convert == PROXY_MAGIC && key->IsNumber()) { |
| key = isolate_->factory()->NumberToString(key); |
| } |
| - int prev_size = properties_->NumberOfElements(); |
| - properties_ = OrderedHashSet::Add(properties_, key); |
| - if (prev_size < properties_->NumberOfElements()) { |
| + int prev_size = string_properties_->NumberOfElements(); |
| + string_properties_ = OrderedHashSet::Add(string_properties_, key); |
| + if (prev_size < string_properties_->NumberOfElements()) { |
| + length_++; |
| + level_string_length_++; |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| + |
| +bool KeyAccumulator::AddSymbolKey(Handle<Object> key) { |
| + if (symbol_properties_.is_null()) { |
| + symbol_properties_ = OrderedHashSet::Allocate(isolate_, 16); |
| + } |
| + int prev_size = symbol_properties_->NumberOfElements(); |
| + symbol_properties_ = OrderedHashSet::Add(symbol_properties_, key); |
| + if (prev_size < symbol_properties_->NumberOfElements()) { |
| length_++; |
| - levelLength_++; |
| + level_symbol_length_++; |
| + return true; |
| + } else { |
| + return false; |
| } |
| - return true; |
| } |
| @@ -7692,7 +7729,7 @@ void KeyAccumulator::AddKeys(Handle<FixedArray> array, |
| if (add_length == 0) return; |
| for (int i = 0; i < add_length; i++) { |
| Handle<Object> current(array->get(i), isolate_); |
| - AddKey(current); |
| + AddKey(current, convert); |
| } |
| } |
| @@ -7713,7 +7750,7 @@ void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) { |
| // Invert the current length to indicate a present proxy, so we can ignore |
| // element keys for this level. Otherwise we would not fully respect the order |
| // given by the proxy. |
| - levelLength_ = -levelLength_; |
| + level_string_length_ = -level_string_length_; |
| } |
| @@ -7727,16 +7764,15 @@ void KeyAccumulator::AddElementKeysFromInterceptor( |
| void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() { |
| - // Sort and remove duplciated from the current elements level and adjust |
| + // Sort and remove duplicated from the current elements level and adjust. |
|
Jakob Kummerow
2015/11/03 15:33:37
nit: s/.//, also s/duplicated/duplicate entries/?
|
| // the lengths accordingly. |
| auto last_level = elements_.back(); |
| size_t nof_removed_keys = last_level->size(); |
| std::sort(last_level->begin(), last_level->end()); |
| last_level->erase(std::unique(last_level->begin(), last_level->end()), |
| last_level->end()); |
| - // Adjust total length / level length by the number of removed duplicates |
| + // Adjust total length by the number of removed duplicates. |
| nof_removed_keys -= last_level->size(); |
| - levelLength_ -= static_cast<int>(nof_removed_keys); |
| length_ -= static_cast<int>(nof_removed_keys); |
| } |
| @@ -7751,10 +7787,12 @@ void KeyAccumulator::SortCurrentElementsList() { |
| void KeyAccumulator::NextPrototype() { |
| // Store the protoLength on the first call of this method. |
| if (!elements_.empty()) { |
| - levelLengths_.push_back(levelLength_); |
| + level_lengths_.push_back(level_string_length_); |
| + level_lengths_.push_back(level_symbol_length_); |
| } |
| elements_.push_back(new std::vector<uint32_t>()); |
| - levelLength_ = 0; |
| + level_string_length_ = 0; |
| + level_symbol_length_ = 0; |
| } |
| @@ -7840,10 +7878,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
| DCHECK(filter == INCLUDE_SYMBOLS); |
| PropertyAttributes attr_filter = |
| static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); |
| - Handle<FixedArray> property_keys = isolate->factory()->NewFixedArray( |
| - current->NumberOfOwnProperties(attr_filter)); |
| - current->GetOwnPropertyNames(*property_keys, 0, attr_filter); |
| - accumulator.AddKeys(property_keys); |
| + current->CollectOwnPropertyNames(&accumulator, attr_filter); |
| } |
| // Add the property keys from the interceptor. |
| @@ -15020,6 +15055,27 @@ int JSObject::GetOwnPropertyNames(FixedArray* storage, int index, |
| } |
| +int JSObject::CollectOwnPropertyNames(KeyAccumulator* keys, |
| + PropertyAttributes filter) { |
| + if (HasFastProperties()) { |
| + int nof_keys = keys->GetLength(); |
| + int real_size = map()->NumberOfOwnDescriptors(); |
| + Handle<DescriptorArray> descs(map()->instance_descriptors()); |
| + for (int i = 0; i < real_size; i++) { |
| + if ((descs->GetDetails(i).attributes() & filter) != 0) continue; |
| + Name* key = descs->GetKey(i); |
| + if (key->FilterKey(filter)) continue; |
| + keys->AddKey(key); |
| + } |
| + return nof_keys - keys->GetLength(); |
| + } else if (IsJSGlobalObject()) { |
| + return global_dictionary()->CollectKeysTo(keys, filter); |
| + } else { |
| + return property_dictionary()->CollectKeysTo(keys, filter); |
| + } |
| +} |
| + |
| + |
| int JSObject::NumberOfOwnElements(PropertyAttributes filter) { |
| // Fast case for objects with no elements. |
| if (!IsJSValue() && HasFastElements()) { |
| @@ -16791,12 +16847,12 @@ int Dictionary<Derived, Shape, Key>::CopyKeysTo( |
| int capacity = this->Capacity(); |
| for (int i = 0; i < capacity; i++) { |
| Object* k = this->KeyAt(i); |
| - if (this->IsKey(k) && !k->FilterKey(filter)) { |
| - if (this->IsDeleted(i)) continue; |
| - PropertyDetails details = this->DetailsAt(i); |
| - PropertyAttributes attr = details.attributes(); |
| - if ((attr & filter) == 0) storage->set(index++, k); |
| - } |
| + if (!this->IsKey(k) || k->FilterKey(filter)) continue; |
| + if (this->IsDeleted(i)) continue; |
| + PropertyDetails details = this->DetailsAt(i); |
| + PropertyAttributes attr = details.attributes(); |
| + if ((attr & filter) != 0) continue; |
| + storage->set(index++, k); |
| } |
| if (sort_mode == Dictionary::SORTED) { |
| storage->SortPairs(storage, index); |
| @@ -16806,6 +16862,24 @@ int Dictionary<Derived, Shape, Key>::CopyKeysTo( |
| } |
| +template <typename Derived, typename Shape, typename Key> |
| +int Dictionary<Derived, Shape, Key>::CollectKeysTo(KeyAccumulator* keys, |
| + PropertyAttributes filter) { |
| + int capacity = this->Capacity(); |
| + int keyLength = keys->GetLength(); |
| + for (int i = 0; i < capacity; i++) { |
| + Object* k = this->KeyAt(i); |
| + if (!this->IsKey(k) || k->FilterKey(filter)) continue; |
| + if (this->IsDeleted(i)) continue; |
| + PropertyDetails details = this->DetailsAt(i); |
| + PropertyAttributes attr = details.attributes(); |
| + if ((attr & filter) != 0) continue; |
| + keys->AddKey(k); |
| + } |
| + return keyLength - keys->GetLength(); |
| +} |
| + |
| + |
| // Backwards lookup (slow). |
| template<typename Derived, typename Shape, typename Key> |
| Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { |