Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1310)

Unified Diff: src/key-accumulator.cc

Issue 1707743002: [key-accumulator] Starting to reimplement the key-accumulator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: WIP fast path for collecting receiver-only elements Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698