| Index: src/keys.cc
|
| diff --git a/src/key-accumulator.cc b/src/keys.cc
|
| similarity index 72%
|
| rename from src/key-accumulator.cc
|
| rename to src/keys.cc
|
| index c2c49969229de3f603ea8494b4543696fef10855..dc696cf10e578ab35b11c4038ea5c274834c2294 100644
|
| --- a/src/key-accumulator.cc
|
| +++ b/src/keys.cc
|
| @@ -2,26 +2,24 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "src/key-accumulator.h"
|
| +#include "src/keys.h"
|
|
|
| #include "src/elements.h"
|
| #include "src/factory.h"
|
| #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();
|
| @@ -86,7 +84,6 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
|
| return result;
|
| }
|
|
|
| -
|
| namespace {
|
|
|
| bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) {
|
| @@ -99,7 +96,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 +132,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 +148,6 @@ bool KeyAccumulator::AddIntegerKey(uint32_t key) {
|
| return true;
|
| }
|
|
|
| -
|
| bool KeyAccumulator::AddStringKey(Handle<Object> key,
|
| AddKeyConversion convert) {
|
| if (string_properties_.is_null()) {
|
| @@ -176,7 +169,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 +184,6 @@ bool KeyAccumulator::AddSymbolKey(Handle<Object> key) {
|
| }
|
| }
|
|
|
| -
|
| void KeyAccumulator::AddKeys(Handle<FixedArray> array,
|
| AddKeyConversion convert) {
|
| int add_length = array->length();
|
| @@ -203,7 +194,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 +201,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
|
| @@ -223,7 +212,6 @@ void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) {
|
| level_string_length_ = -level_string_length_;
|
| }
|
|
|
| -
|
| MaybeHandle<FixedArray> FilterProxyKeys(Isolate* isolate, Handle<JSProxy> owner,
|
| Handle<FixedArray> keys,
|
| PropertyFilter filter) {
|
| @@ -253,7 +241,6 @@ MaybeHandle<FixedArray> FilterProxyKeys(Isolate* isolate, Handle<JSProxy> owner,
|
| return keys;
|
| }
|
|
|
| -
|
| // Returns "nothing" in case of exception, "true" on success.
|
| Maybe<bool> KeyAccumulator::AddKeysFromProxy(Handle<JSProxy> proxy,
|
| Handle<FixedArray> keys) {
|
| @@ -277,7 +264,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 +272,6 @@ void KeyAccumulator::AddElementKeysFromInterceptor(
|
| SortCurrentElementsListRemoveDuplicates();
|
| }
|
|
|
| -
|
| void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() {
|
| // Sort and remove duplicates from the current elements level and adjust.
|
| // the lengths accordingly.
|
| @@ -300,14 +285,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 +302,125 @@ void KeyAccumulator::NextPrototype() {
|
| level_symbol_length_ = 0;
|
| }
|
|
|
| +namespace {
|
| +
|
| +void TrySettingEmptyEnumCache(JSReceiver* object) {
|
| + Map* map = object->map();
|
| + DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
|
| + if (!map->OnlyHasSimpleProperties()) return;
|
| + if (map->IsJSProxyMap()) return;
|
| + if (map->NumberOfOwnDescriptors() > 0) {
|
| + int number_of_enumerable_own_properties =
|
| + map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
|
| + if (number_of_enumerable_own_properties > 0) return;
|
| + }
|
| + DCHECK(object->IsJSObject());
|
| + map->SetEnumLength(0);
|
| +}
|
| +
|
| +bool CheckAndInitalizeSimpleEnumCache(JSReceiver* object) {
|
| + if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
|
| + TrySettingEmptyEnumCache(object);
|
| + }
|
| + if (object->map()->EnumLength() != 0) return false;
|
| + DCHECK(object->IsJSObject());
|
| + return !JSObject::cast(object)->HasEnumerableElements();
|
| +}
|
| +} // 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_receiver_simple_enum_ = false;
|
| + has_empty_prototype_ = true;
|
| + JSReceiver* first_non_empty_prototype;
|
| + for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
|
| + iter.Advance()) {
|
| + JSReceiver* current = iter.GetCurrent<JSReceiver>();
|
| + if (CheckAndInitalizeSimpleEnumCache(current)) continue;
|
| + has_empty_prototype_ = false;
|
| + first_non_empty_prototype = current;
|
| + // TODO(cbruni): use the first non-empty prototype.
|
| + USE(first_non_empty_prototype);
|
| + return;
|
| + }
|
| + DCHECK(has_empty_prototype_);
|
| + is_receiver_simple_enum_ =
|
| + receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
|
| + !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,
|
| + ONLY_ENUMERABLE);
|
| +}
|
| +
|
| +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()) {
|
| + // Assume that there are elements.
|
| + 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_->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_receiver_simple_enum_ =
|
| + object->map()->EnumLength() != kInvalidEnumCacheSentinel;
|
| + return keys;
|
| + }
|
| + }
|
| + // The properties-only case failed because there were probably elements on the
|
| + // receiver.
|
| + return GetOwnKeysWithElements(isolate_, object, convert);
|
| +}
|
| +
|
| +MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
|
| + GetKeysConversion convert) {
|
| + return JSReceiver::GetKeys(receiver_, type_, ENUMERABLE_STRINGS);
|
| +}
|
|
|
| } // namespace internal
|
| } // namespace v8
|
|
|