Commit 4693fdf9 authored by Zhang, Shiyu's avatar Zhang, Shiyu Committed by Commit Bot

[runtime] Add fast path for ConvertToKeysArray

... for the case we haven't seen any elements on the entire prototype chain.

Contributed by tao.pan@intel.com

Change-Id: Ied7d1a918b545e71d94ab1521bf0d233ea15cfce
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1848960Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Shiyu Zhang <shiyu.zhang@intel.com>
Cr-Commit-Position: refs/heads/master@{#64261}
parent 568d5100
......@@ -3518,7 +3518,7 @@ enum class IndexFilter { kIncludeIndices, kSkipIndices };
* kConvertToString will convert integer indices to strings.
* kKeepNumbers will return numbers for integer indices.
*/
enum class KeyConversionMode { kConvertToString, kKeepNumbers };
enum class KeyConversionMode { kConvertToString, kKeepNumbers, kNoNumbers };
/**
* Integrity level for objects.
......
......@@ -279,9 +279,13 @@ void FastKeyAccumulator::Prepare() {
is_receiver_simple_enum_ = false;
has_empty_prototype_ = true;
JSReceiver last_prototype;
may_have_elements_ = MayHaveElements(*receiver_);
for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
iter.Advance()) {
JSReceiver current = iter.GetCurrent<JSReceiver>();
if (!may_have_elements_) {
may_have_elements_ = MayHaveElements(current);
}
bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
if (has_no_properties) continue;
last_prototype = current;
......@@ -498,12 +502,21 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
accumulator.set_is_for_in(is_for_in_);
accumulator.set_skip_indices(skip_indices_);
accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
accumulator.set_may_have_elements(may_have_elements_);
MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
MaybeHandle<FixedArray>());
return accumulator.GetKeys(keys_conversion);
}
bool FastKeyAccumulator::MayHaveElements(JSReceiver receiver) {
if (!receiver.IsJSObject()) return true;
JSObject object = JSObject::cast(receiver);
if (object.HasEnumerableElements()) return true;
if (object.HasIndexedInterceptor()) return true;
return false;
}
namespace {
enum IndexedOrNamed { kIndexed, kNamed };
......@@ -825,7 +838,9 @@ Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
return Just(true);
}
MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>());
if (may_have_elements_) {
MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>());
}
MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>());
return Just(true);
}
......
......@@ -93,6 +93,7 @@ class KeyAccumulator final {
void set_last_non_empty_prototype(Handle<JSReceiver> object) {
last_non_empty_prototype_ = object;
}
void set_may_have_elements(bool value) { may_have_elements_ = value; }
// Shadowing keys are used to filter keys. This happens when non-enumerable
// keys appear again on the prototype chain.
void AddShadowingKey(Object key);
......@@ -125,6 +126,7 @@ class KeyAccumulator final {
// For all the keys on the first receiver adding a shadowing key we can skip
// the shadow check.
bool skip_shadow_check_ = true;
bool may_have_elements_ = true;
DISALLOW_COPY_AND_ASSIGN(KeyAccumulator);
};
......@@ -149,6 +151,7 @@ class FastKeyAccumulator {
bool is_receiver_simple_enum() { return is_receiver_simple_enum_; }
bool has_empty_prototype() { return has_empty_prototype_; }
bool may_have_elements() { return may_have_elements_; }
MaybeHandle<FixedArray> GetKeys(
GetKeysConversion convert = GetKeysConversion::kKeepNumbers);
......@@ -160,6 +163,8 @@ class FastKeyAccumulator {
MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache();
bool MayHaveElements(JSReceiver receiver);
Isolate* isolate_;
Handle<JSReceiver> receiver_;
Handle<JSReceiver> last_non_empty_prototype_;
......@@ -169,6 +174,7 @@ class FastKeyAccumulator {
bool skip_indices_ = false;
bool is_receiver_simple_enum_ = false;
bool has_empty_prototype_ = false;
bool may_have_elements_ = true;
DISALLOW_COPY_AND_ASSIGN(FastKeyAccumulator);
};
......
......@@ -786,7 +786,8 @@ enum AccessorComponent { ACCESSOR_GETTER, ACCESSOR_SETTER };
enum class GetKeysConversion {
kKeepNumbers = static_cast<int>(v8::KeyConversionMode::kKeepNumbers),
kConvertToString = static_cast<int>(v8::KeyConversionMode::kConvertToString)
kConvertToString = static_cast<int>(v8::KeyConversionMode::kConvertToString),
kNoNumbers = static_cast<int>(v8::KeyConversionMode::kNoNumbers)
};
enum class KeyCollectionMode {
......
......@@ -168,8 +168,8 @@ Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
for (int i = 0; i < length; i++) {
int index = HashTableStartIndex() + nof_buckets + (i * kEntrySize);
Object key = table->get(index);
uint32_t index_value;
if (convert == GetKeysConversion::kConvertToString) {
uint32_t index_value;
if (key.ToArrayIndex(&index_value)) {
// Avoid trashing the Number2String cache if indices get very large.
bool use_cache = i < kMaxStringTableEntries;
......@@ -177,6 +177,8 @@ Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
} else {
CHECK(key.IsName());
}
} else if (convert == GetKeysConversion::kNoNumbers) {
DCHECK(!key.ToArrayIndex(&index_value));
}
result->set(i, key);
}
......
......@@ -33,7 +33,10 @@ MaybeHandle<HeapObject> Enumerate(Isolate* isolate,
if (!accumulator.is_receiver_simple_enum()) {
Handle<FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, keys, accumulator.GetKeys(GetKeysConversion::kConvertToString),
isolate, keys,
accumulator.GetKeys(accumulator.may_have_elements()
? GetKeysConversion::kConvertToString
: GetKeysConversion::kNoNumbers),
HeapObject);
// Test again, since cache may have been built by GetKeys() calls above.
if (!accumulator.is_receiver_simple_enum()) return keys;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment