Chromium Code Reviews| Index: src/key-accumulator.cc |
| diff --git a/src/key-accumulator.cc b/src/key-accumulator.cc |
| index c2c49969229de3f603ea8494b4543696fef10855..becdda15f2be2ba25822a1303daffe00abc9d837 100644 |
| --- a/src/key-accumulator.cc |
| +++ b/src/key-accumulator.cc |
| @@ -9,19 +9,17 @@ |
| #include "src/isolate-inl.h" |
| #include "src/objects-inl.h" |
| #include "src/property-descriptor.h" |
| - |
| +#include "src/prototype.h" |
| namespace v8 { |
| namespace internal { |
| - |
| KeyAccumulator::~KeyAccumulator() { |
| for (size_t i = 0; i < elements_.size(); i++) { |
| delete elements_[i]; |
| } |
| } |
| - |
| Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
| if (length_ == 0) { |
| return isolate_->factory()->empty_fixed_array(); |
| @@ -99,7 +97,6 @@ bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { |
| return AddKey(handle(key, isolate_), convert); |
| } |
| - |
| bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| if (key->IsSymbol()) { |
| if (filter_ & SKIP_SYMBOLS) return false; |
| @@ -136,10 +133,8 @@ bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| return AddStringKey(key, convert); |
| } |
| - |
| bool KeyAccumulator::AddKey(uint32_t key) { return AddIntegerKey(key); } |
| - |
| bool KeyAccumulator::AddIntegerKey(uint32_t key) { |
| // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). |
| // We mark proxy-levels with a negative length |
| @@ -154,7 +149,6 @@ bool KeyAccumulator::AddIntegerKey(uint32_t key) { |
| return true; |
| } |
| - |
| bool KeyAccumulator::AddStringKey(Handle<Object> key, |
| AddKeyConversion convert) { |
| if (string_properties_.is_null()) { |
| @@ -176,7 +170,6 @@ bool KeyAccumulator::AddStringKey(Handle<Object> key, |
| } |
| } |
| - |
| bool KeyAccumulator::AddSymbolKey(Handle<Object> key) { |
| if (symbol_properties_.is_null()) { |
| symbol_properties_ = OrderedHashSet::Allocate(isolate_, 16); |
| @@ -192,7 +185,6 @@ bool KeyAccumulator::AddSymbolKey(Handle<Object> key) { |
| } |
| } |
| - |
| void KeyAccumulator::AddKeys(Handle<FixedArray> array, |
| AddKeyConversion convert) { |
| int add_length = array->length(); |
| @@ -203,7 +195,6 @@ void KeyAccumulator::AddKeys(Handle<FixedArray> array, |
| } |
| } |
| - |
| void KeyAccumulator::AddKeys(Handle<JSObject> array_like, |
| AddKeyConversion convert) { |
| DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); |
| @@ -211,7 +202,6 @@ void KeyAccumulator::AddKeys(Handle<JSObject> array_like, |
| accessor->AddElementsToKeyAccumulator(array_like, this, convert); |
| } |
| - |
| void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) { |
| // Proxies define a complete list of keys with no distinction of |
| // elements and properties, which breaks the normal assumption for the |
| @@ -277,7 +267,6 @@ Maybe<bool> KeyAccumulator::AddKeysFromProxy(Handle<JSProxy> proxy, |
| return Just(true); |
| } |
| - |
| void KeyAccumulator::AddElementKeysFromInterceptor( |
| Handle<JSObject> array_like) { |
| AddKeys(array_like, CONVERT_TO_ARRAY_INDEX); |
| @@ -286,7 +275,6 @@ void KeyAccumulator::AddElementKeysFromInterceptor( |
| SortCurrentElementsListRemoveDuplicates(); |
| } |
| - |
| void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() { |
| // Sort and remove duplicates from the current elements level and adjust. |
| // the lengths accordingly. |
| @@ -300,14 +288,12 @@ void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() { |
| length_ -= static_cast<int>(nof_removed_keys); |
| } |
| - |
| void KeyAccumulator::SortCurrentElementsList() { |
| if (elements_.empty()) return; |
| auto element_keys = elements_.back(); |
| std::sort(element_keys->begin(), element_keys->end()); |
| } |
| - |
| void KeyAccumulator::NextPrototype() { |
| // Store the protoLength on the first call of this method. |
| if (!elements_.empty()) { |
| @@ -319,6 +305,133 @@ void KeyAccumulator::NextPrototype() { |
| level_symbol_length_ = 0; |
| } |
| +// ============================================================================ |
| +void FastKeyAccumulator::UseVars() { |
| + USE(type_); |
| + USE(filter_); |
| +} |
| + |
| +namespace { |
| + |
| +bool TrySettingEmptyEnumCache(JSReceiver* object) { |
| + Map* map = object->map(); |
| + if (!map->OnlyHasSimpleProperties()) return false; |
| + if (map->IsJSProxyMap()) return false; |
| + if (map->NumberOfOwnDescriptors() > 0) { |
| + int number_of_enumerable_own_properties = |
| + map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS); |
| + if (number_of_enumerable_own_properties > 0) return false; |
| + } |
| + DCHECK(object->IsJSObject()); |
| + if (JSObject::cast(object)->HasEnumerableElements()) return false; |
| + object->map()->SetEnumLength(0); |
| + return true; |
| +} |
| + |
| +bool CheckAndInitalizeSimpleEnumCache(JSReceiver* object) { |
| + int enum_length = object->map()->EnumLength(); |
| + if (enum_length == kInvalidEnumCacheSentinel) { |
| + return TrySettingEmptyEnumCache(object); |
| + } else if (enum_length == 0) { |
| + DCHECK(object->IsJSObject()); |
| + return !JSObject::cast(object)->HasEnumerableElements(); |
| + } |
| + return false; |
| +} |
| +} // namespace |
| + |
| +void FastKeyAccumulator::Prepare() { |
| + DisallowHeapAllocation no_gc; |
| + // Directly go for the fast path for OWN_ONLY keys. |
| + if (type_ == OWN_ONLY) return; |
| + // Fully walk the prototype chain and find the last prototype with keys. |
| + is_simple_enum_ = false; |
| + has_empty_prototype_ = true; |
| + JSReceiver* first_non_empty_prototype; |
| + |
| + for (PrototypeIterator iter(isolate_, *receiver_, |
| + PrototypeIterator::START_AT_PROTOTYPE); |
| + !iter.IsAtEnd(); iter.Advance()) { |
| + JSReceiver* current = iter.GetCurrent<JSReceiver>(); |
| + if (CheckAndInitalizeSimpleEnumCache(current)) continue; |
| + has_empty_prototype_ = false; |
| + first_non_empty_prototype = current; |
| + return; |
| + } |
| + DCHECK(has_empty_prototype_); |
| + if (receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel) { |
| + is_simple_enum_ = !JSObject::cast(*receiver_)->HasEnumerableElements(); |
| + } |
| +} |
| + |
| +namespace { |
| +Handle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, |
| + Handle<JSObject> object, |
| + GetKeysConversion convert) { |
| + Handle<FixedArray> keys = JSObject::GetFastEnumPropertyKeys(isolate, object); |
| + ElementsAccessor* accessor = object->GetElementsAccessor(); |
| + return accessor->PrependElementIndices(object, keys, convert); |
| +} |
| + |
| +MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache( |
| + Isolate* isolate, Handle<JSObject> object) { |
| + // Uninitalized enum cache |
| + Map* map = object->map(); |
| + if (object->elements() != isolate->heap()->empty_fixed_array() || |
| + object->elements() != isolate->heap()->empty_slow_element_dictionary()) { |
| + // TODO(cbruni): avoud HasEnumerableElements for very large holey elements. |
|
Toon Verwaest
2016/02/24 15:07:06
avoid
|
| + if (object->HasEnumerableElements()) return MaybeHandle<FixedArray>(); |
| + } |
| + int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
| + if (number_of_own_descriptors == 0) { |
| + map->SetEnumLength(0); |
| + return isolate->factory()->empty_fixed_array(); |
| + } |
| + // We have no elements but possibly enumerable property keys, hence we can |
| + // directly initialize the enum cache. |
| + return JSObject::GetFastEnumPropertyKeys(isolate, object); |
| +} |
| + |
| +} // namespace |
| + |
| +MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { |
| + Handle<FixedArray> keys; |
| + if (GetKeysFast(convert).ToHandle(&keys)) { |
| + return keys; |
| + } |
| + return GetKeysSlow(convert); |
| +} |
| + |
| +MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( |
| + GetKeysConversion convert) { |
| + bool own_only = has_empty_prototype_ || type_ == OWN_ONLY; |
| + if (!own_only || receiver_->IsJSProxy() || |
| + !receiver_->map()->OnlyHasSimpleProperties()) { |
| + return MaybeHandle<FixedArray>(); |
| + } |
| + |
| + Handle<FixedArray> keys; |
| + DCHECK(receiver_->IsJSObject()); |
| + Handle<JSObject> object = Handle<JSObject>::cast(receiver_); |
| + |
| + int enum_length = receiver_->map()->EnumLength(); |
| + if (enum_length == kInvalidEnumCacheSentinel) { |
| + // Try initializing the enum cache and return own properties. |
| + if (GetOwnKeysWithUninitializedEnumCache(isolate_, object) |
| + .ToHandle(&keys)) { |
| + is_simple_enum_ = |
| + object->map()->EnumLength() != kInvalidEnumCacheSentinel; |
| + return keys; |
| + } |
| + } |
| + DCHECK(object->HasEnumerableElements()); |
| + return GetOwnKeysWithElements(isolate_, object, convert); |
| +} |
| + |
| +MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( |
| + GetKeysConversion convert) { |
| + return JSReceiver::GetKeys(receiver_, type_, ENUMERABLE_STRINGS); |
| +} |
| } // namespace internal |
| } // namespace v8 |