Revert of [key-accumulator] Starting to reimplement the key-accumulator (patchset #15 id:280001 of https://codereview.chromium.org/1707743002/ )

Reason for revert:
gcmole again

Original issue's description:
> [key-accumulator] Starting to reimplement the key-accumulator
>
> Introducing the KeyAccumulator accidentally removed some crucial fast-paths.
> This CL starts rewriting the KeyAccumulator, step-by-step introducing the
> special cases again.
>
> BUG=chromium:545503, v8:4758
> LOG=y
>
> Committed: https://crrev.com/9c61327ecb2ee41f34232632e0cac93202bae6b7
> Cr-Commit-Position: refs/heads/master@{#34532}
>
> Committed: https://crrev.com/b954c872aac60657b400079b7333216ea658dc8a
> Cr-Commit-Position: refs/heads/master@{#34548}

TBR=verwaest@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:545503, v8:4758

Review URL: https://codereview.chromium.org/1769043003

Cr-Commit-Position: refs/heads/master@{#34551}
This commit is contained in:
cbruni 2016-03-07 08:36:18 -08:00 committed by Commit bot
parent 1d7da9c639
commit 4fdf56448b
12 changed files with 98 additions and 396 deletions

View File

@ -1139,8 +1139,8 @@ source_set("v8_base") {
"src/isolate.h",
"src/json-parser.h",
"src/json-stringifier.h",
"src/keys.h",
"src/keys.cc",
"src/key-accumulator.h",
"src/key-accumulator.cc",
"src/layout-descriptor-inl.h",
"src/layout-descriptor.cc",
"src/layout-descriptor.h",

View File

@ -428,6 +428,7 @@ static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
}
}
static void TraceTopFrame(Isolate* isolate) {
StackFrameIterator it(isolate);
if (it.done()) {
@ -709,16 +710,6 @@ class ElementsAccessorBase : public ElementsAccessor {
JSObject::ValidateElements(array);
}
static uint32_t GetIterationLength(JSObject* receiver,
FixedArrayBase* elements) {
if (receiver->IsJSArray()) {
return static_cast<uint32_t>(
Smi::cast(JSArray::cast(receiver)->length())->value());
} else {
return ElementsAccessorSubclass::GetCapacityImpl(receiver, elements);
}
}
static Handle<FixedArrayBase> ConvertElementsWithCapacity(
Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
ElementsKind from_kind, uint32_t capacity) {
@ -835,14 +826,6 @@ class ElementsAccessorBase : public ElementsAccessor {
from, from_start, *to, from_kind, to_start, packed_size, copy_size);
}
void CollectElementIndices(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range,
PropertyFilter filter, uint32_t offset) final {
ElementsAccessorSubclass::CollectElementIndicesImpl(
object, backing_store, keys, range, filter, offset);
}
static void CollectElementIndicesImpl(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range,
@ -853,102 +836,30 @@ class ElementsAccessorBase : public ElementsAccessor {
// Non-dictionary elements can't have all-can-read accessors.
return;
}
uint32_t length = GetIterationLength(*object, *backing_store);
uint32_t length = 0;
if (object->IsJSArray()) {
length = Smi::cast(JSArray::cast(*object)->length())->value();
} else {
length =
ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
}
if (range < length) length = range;
for (uint32_t i = offset; i < length; i++) {
if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
filter)) {
keys->AddKey(i);
if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
filter)) {
continue;
}
keys->AddKey(i);
}
}
static Handle<FixedArray> DirectCollectElementIndicesImpl(
Isolate* isolate, Handle<JSObject> object,
Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices) {
uint32_t length =
ElementsAccessorSubclass::GetIterationLength(*object, *backing_store);
uint32_t insertion_index = 0;
for (uint32_t i = 0; i < length; i++) {
if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
filter)) {
if (convert == CONVERT_TO_STRING) {
list->set(insertion_index, *isolate->factory()->Uint32ToString(i));
} else {
list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
}
insertion_index++;
}
}
*nof_indices = insertion_index;
return list;
}
Handle<FixedArray> PrependElementIndices(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store,
Handle<FixedArray> keys,
GetKeysConversion convert,
PropertyFilter filter) final {
return ElementsAccessorSubclass::PrependElementIndicesImpl(
object, backing_store, keys, convert, filter);
}
static Handle<FixedArray> PrependElementIndicesImpl(
Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
Handle<FixedArray> keys, GetKeysConversion convert,
PropertyFilter filter) {
Isolate* isolate = object->GetIsolate();
uint32_t nof_property_keys = keys->length();
uint32_t initial_list_length =
ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
initial_list_length += nof_property_keys;
// Collect the element indices into a new list.
uint32_t nof_indices = 0;
Handle<FixedArray> combined_keys =
isolate->factory()->NewFixedArray(initial_list_length);
combined_keys = ElementsAccessorSubclass::DirectCollectElementIndicesImpl(
isolate, object, backing_store, convert, filter, combined_keys,
&nof_indices);
// Sort the indices list if necessary.
if (IsDictionaryElementsKind(kind())) {
struct {
bool operator()(Object* a, Object* b) {
if (!a->IsUndefined()) {
if (b->IsUndefined()) return true;
return a->Number() < b->Number();
}
return !b->IsUndefined();
}
} cmp;
Object** start =
reinterpret_cast<Object**>(combined_keys->GetFirstElementAddress());
std::sort(start, start + nof_indices, cmp);
// Indices from dictionary elements should only be converted after
// sorting.
if (convert == CONVERT_TO_STRING) {
for (uint32_t i = 0; i < nof_indices; i++) {
combined_keys->set(i, *isolate->factory()->Uint32ToString(
combined_keys->get(i)->Number()));
}
}
}
// Copy over the passed-in property keys.
CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys,
FAST_ELEMENTS, nof_indices, nof_property_keys);
if (IsHoleyElementsKind(kind())) {
// Shrink combined_keys to the final size.
int final_size = nof_indices + nof_property_keys;
DCHECK_LE(final_size, combined_keys->length());
combined_keys->Shrink(final_size);
}
return combined_keys;
}
void CollectElementIndices(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range,
PropertyFilter filter, uint32_t offset) final {
ElementsAccessorSubclass::CollectElementIndicesImpl(
object, backing_store, keys, range, filter, offset);
};
void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
@ -981,7 +892,12 @@ class ElementsAccessorBase : public ElementsAccessor {
? index
: kMaxUInt32;
} else {
uint32_t length = GetIterationLength(holder, backing_store);
uint32_t length =
holder->IsJSArray()
? static_cast<uint32_t>(
Smi::cast(JSArray::cast(holder)->length())->value())
: ElementsAccessorSubclass::GetCapacityImpl(holder,
backing_store);
return index < length ? index : kMaxUInt32;
}
}
@ -1183,28 +1099,6 @@ class DictionaryElementsAccessor
return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
}
static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
int entry, PropertyFilter filter) {
DisallowHeapAllocation no_gc;
Object* raw_key = dictionary->KeyAt(entry);
if (!dictionary->IsKey(raw_key)) return kMaxUInt32;
if (raw_key->FilterKey(filter)) return kMaxUInt32;
if (dictionary->IsDeleted(entry)) return kMaxUInt32;
DCHECK(raw_key->IsNumber());
DCHECK_LE(raw_key->Number(), kMaxUInt32);
uint32_t key = static_cast<uint32_t>(raw_key->Number());
PropertyDetails details = dictionary->DetailsAt(entry);
if (filter & ONLY_ALL_CAN_READ) {
if (details.kind() != kAccessor) return kMaxUInt32;
Object* accessors = dictionary->ValueAt(entry);
if (!accessors->IsAccessorInfo()) return kMaxUInt32;
if (!AccessorInfo::cast(accessors)->all_can_read()) return kMaxUInt32;
}
PropertyAttributes attr = details.attributes();
if ((attr & filter) != 0) return kMaxUInt32;
return key;
}
static void CollectElementIndicesImpl(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range,
@ -1214,32 +1108,29 @@ class DictionaryElementsAccessor
Handle<SeededNumberDictionary>::cast(backing_store);
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
uint32_t key = GetKeyForEntryImpl(dictionary, i, filter);
if (key == kMaxUInt32) continue;
keys->AddKey(key);
Object* k = dictionary->KeyAt(i);
if (!dictionary->IsKey(k)) continue;
if (k->FilterKey(filter)) continue;
if (dictionary->IsDeleted(i)) continue;
DCHECK(k->IsNumber());
DCHECK_LE(k->Number(), kMaxUInt32);
uint32_t index = static_cast<uint32_t>(k->Number());
if (index < offset) continue;
PropertyDetails details = dictionary->DetailsAt(i);
if (filter & ONLY_ALL_CAN_READ) {
if (details.kind() != kAccessor) continue;
Object* accessors = dictionary->ValueAt(i);
if (!accessors->IsAccessorInfo()) continue;
if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
}
PropertyAttributes attr = details.attributes();
if ((attr & filter) != 0) continue;
keys->AddKey(index);
}
keys->SortCurrentElementsList();
}
static Handle<FixedArray> DirectCollectElementIndicesImpl(
Isolate* isolate, Handle<JSObject> object,
Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices) {
Handle<SeededNumberDictionary> dictionary =
Handle<SeededNumberDictionary>::cast(backing_store);
uint32_t capacity = dictionary->Capacity();
uint32_t insertion_index = 0;
for (uint32_t i = 0; i < capacity; i++) {
uint32_t key = GetKeyForEntryImpl(dictionary, i, filter);
if (key == kMaxUInt32) continue;
list->set(insertion_index, *isolate->factory()->NewNumberFromUint(key));
insertion_index++;
}
*nof_indices = insertion_index;
return list;
}
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
AddKeyConversion convert) {
@ -1404,10 +1295,15 @@ class FastElementsAccessor
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
AddKeyConversion convert) {
uint32_t length = 0;
Handle<FixedArrayBase> elements(receiver->elements(),
receiver->GetIsolate());
uint32_t length =
FastElementsAccessorSubclass::GetIterationLength(*receiver, *elements);
if (receiver->IsJSArray()) {
length = Smi::cast(JSArray::cast(*receiver)->length())->value();
} else {
length =
FastElementsAccessorSubclass::GetCapacityImpl(*receiver, *elements);
}
for (uint32_t i = 0; i < length; i++) {
if (IsFastPackedElementsKind(KindTraits::Kind) ||
HasEntryImpl(*elements, i)) {

View File

@ -8,7 +8,7 @@
#include "src/elements-kind.h"
#include "src/heap/heap.h"
#include "src/isolate.h"
#include "src/keys.h"
#include "src/key-accumulator.h"
#include "src/objects.h"
namespace v8 {
@ -94,19 +94,6 @@ class ElementsAccessor {
filter, offset);
}
//
virtual Handle<FixedArray> PrependElementIndices(
Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
Handle<FixedArray> keys, GetKeysConversion convert,
PropertyFilter filter = ALL_PROPERTIES) = 0;
inline Handle<FixedArray> PrependElementIndices(
Handle<JSObject> object, Handle<FixedArray> keys,
GetKeysConversion convert, PropertyFilter filter = ALL_PROPERTIES) {
return PrependElementIndices(object, handle(object->elements()), keys,
convert, filter);
}
virtual void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
AddKeyConversion convert) = 0;

View File

@ -2,24 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/keys.h"
#include "src/key-accumulator.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();
@ -84,6 +86,7 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
return result;
}
namespace {
bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) {
@ -96,6 +99,7 @@ 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;
@ -132,8 +136,10 @@ 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
@ -148,6 +154,7 @@ bool KeyAccumulator::AddIntegerKey(uint32_t key) {
return true;
}
bool KeyAccumulator::AddStringKey(Handle<Object> key,
AddKeyConversion convert) {
if (string_properties_.is_null()) {
@ -169,6 +176,7 @@ bool KeyAccumulator::AddStringKey(Handle<Object> key,
}
}
bool KeyAccumulator::AddSymbolKey(Handle<Object> key) {
if (symbol_properties_.is_null()) {
symbol_properties_ = OrderedHashSet::Allocate(isolate_, 16);
@ -184,6 +192,7 @@ bool KeyAccumulator::AddSymbolKey(Handle<Object> key) {
}
}
void KeyAccumulator::AddKeys(Handle<FixedArray> array,
AddKeyConversion convert) {
int add_length = array->length();
@ -194,6 +203,7 @@ void KeyAccumulator::AddKeys(Handle<FixedArray> array,
}
}
void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
AddKeyConversion convert) {
DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
@ -201,6 +211,7 @@ 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
@ -212,6 +223,7 @@ 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) {
@ -241,6 +253,7 @@ 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) {
@ -264,6 +277,7 @@ Maybe<bool> KeyAccumulator::AddKeysFromProxy(Handle<JSProxy> proxy,
return Just(true);
}
void KeyAccumulator::AddElementKeysFromInterceptor(
Handle<JSObject> array_like) {
AddKeys(array_like, CONVERT_TO_ARRAY_INDEX);
@ -272,6 +286,7 @@ void KeyAccumulator::AddElementKeysFromInterceptor(
SortCurrentElementsListRemoveDuplicates();
}
void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() {
// Sort and remove duplicates from the current elements level and adjust.
// the lengths accordingly.
@ -285,12 +300,14 @@ 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()) {
@ -302,125 +319,6 @@ 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

View File

@ -86,40 +86,9 @@ class KeyAccumulator final BASE_EMBEDDED {
DISALLOW_COPY_AND_ASSIGN(KeyAccumulator);
};
// The FastKeyAccumulator handles the cases where there are no elements on the
// prototype chain and forwords the complex/slow cases to the normal
// KeyAccumulator.
class FastKeyAccumulator {
public:
FastKeyAccumulator(Isolate* isolate, Handle<JSReceiver> receiver,
KeyCollectionType type, PropertyFilter filter)
: isolate_(isolate), receiver_(receiver), type_(type), filter_(filter) {
Prepare();
// TODO(cbruni): pass filter_ directly to the KeyAccumulator.
USE(filter_);
}
bool is_receiver_simple_enum() { return is_receiver_simple_enum_; }
bool has_empty_prototype() { return has_empty_prototype_; }
MaybeHandle<FixedArray> GetKeys(GetKeysConversion convert = KEEP_NUMBERS);
private:
void Prepare();
MaybeHandle<FixedArray> GetKeysFast(GetKeysConversion convert);
MaybeHandle<FixedArray> GetKeysSlow(GetKeysConversion convert);
Isolate* isolate_;
Handle<JSReceiver> receiver_;
KeyCollectionType type_;
PropertyFilter filter_;
bool is_receiver_simple_enum_ = false;
bool has_empty_prototype_ = false;
DISALLOW_COPY_AND_ASSIGN(FastKeyAccumulator);
};
} // namespace internal
} // namespace v8
#endif // V8_KEY_ACCUMULATOR_H_

View File

@ -455,12 +455,6 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
}
os << "\n - elements kind: " << ElementsKindToString(elements_kind());
os << "\n - unused property fields: " << unused_property_fields();
os << "\n - enum length: ";
if (EnumLength() == kInvalidEnumCacheSentinel) {
os << "invalid";
} else {
os << EnumLength();
}
if (is_deprecated()) os << "\n - deprecated_map";
if (is_stable()) os << "\n - stable_map";
if (is_dictionary_map()) os << "\n - dictionary_map";

View File

@ -34,7 +34,7 @@
#include "src/interpreter/bytecodes.h"
#include "src/interpreter/source-position-table.h"
#include "src/isolate-inl.h"
#include "src/keys.h"
#include "src/key-accumulator.h"
#include "src/list.h"
#include "src/log.h"
#include "src/lookup.h"
@ -8226,9 +8226,7 @@ MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
bool JSObject::HasEnumerableElements() {
// TODO(cbruni): cleanup
JSObject* object = this;
bool HasEnumerableElements(JSObject* object) {
switch (object->GetElementsKind()) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
@ -8293,6 +8291,7 @@ bool JSObject::HasEnumerableElements() {
return true;
}
// Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks).
@ -8309,7 +8308,7 @@ bool JSReceiver::IsSimpleEnum() {
if (current->IsAccessCheckNeeded()) return false;
DCHECK(!current->HasNamedInterceptor());
DCHECK(!current->HasIndexedInterceptor());
if (current->HasEnumerableElements()) return false;
if (HasEnumerableElements(current)) return false;
if (current != this && enum_length != 0) return false;
}
return true;
@ -8373,9 +8372,10 @@ bool Map::OnlyHasSimpleProperties() {
!has_hidden_prototype() && !is_dictionary_map();
}
// static
Handle<FixedArray> JSObject::GetFastEnumPropertyKeys(Isolate* isolate,
Handle<JSObject> object) {
namespace {
Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
Handle<JSObject> object) {
Handle<Map> map(object->map());
bool cache_enum_length = map->OnlyHasSimpleProperties();
@ -8426,9 +8426,8 @@ Handle<FixedArray> JSObject::GetFastEnumPropertyKeys(Isolate* isolate,
for (int i = 0; i < size; i++) {
PropertyDetails details = descs->GetDetails(i);
if (details.IsDontEnum()) continue;
Object* key = descs->GetKey(i);
if (key->IsSymbol()) continue;
if (details.IsDontEnum() || key->IsSymbol()) continue;
storage->set(index, key);
if (!indices.is_null()) {
if (details.type() != DATA) {
@ -8450,6 +8449,7 @@ Handle<FixedArray> JSObject::GetFastEnumPropertyKeys(Isolate* isolate,
return storage;
}
} // namespace
Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object) {
Isolate* isolate = object->GetIsolate();
@ -10665,6 +10665,7 @@ Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
return array;
}
Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
Handle<Object> obj2, AddMode mode) {
int length = array->Length();
@ -16426,6 +16427,7 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
}
}
void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
PropertyFilter filter) {
if (HasFastProperties()) {
@ -16466,6 +16468,7 @@ int JSObject::NumberOfOwnElements(PropertyFilter filter) {
return GetOwnElementKeys(NULL, filter);
}
void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
KeyAccumulator* keys,
PropertyFilter filter) {
@ -18473,6 +18476,7 @@ int Dictionary<Derived, Shape, Key>::CopyKeysTo(
return index - start_index;
}
template <typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::CollectKeysTo(
Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,

View File

@ -2043,8 +2043,6 @@ class JSObject: public JSReceiver {
inline bool HasSlowArgumentsElements();
inline bool HasFastStringWrapperElements();
inline bool HasSlowStringWrapperElements();
bool HasEnumerableElements();
inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
// Requires: HasFastElements().
@ -2294,9 +2292,6 @@ class JSObject: public JSReceiver {
static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object);
static Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
Handle<JSObject> object);
// Returns a new map with all transitions dropped from the object's current
// map and the ElementsKind set.
static Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,

View File

@ -9,7 +9,7 @@
#include "src/elements.h"
#include "src/factory.h"
#include "src/isolate-inl.h"
#include "src/keys.h"
#include "src/key-accumulator.h"
#include "src/messages.h"
#include "src/prototype.h"

View File

@ -5,10 +5,8 @@
#include "src/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/elements.h"
#include "src/factory.h"
#include "src/isolate-inl.h"
#include "src/keys.h"
#include "src/objects-inl.h"
namespace v8 {
@ -22,15 +20,15 @@ namespace {
// deletions during a for-in.
MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) {
Isolate* const isolate = receiver->GetIsolate();
FastKeyAccumulator accumulator(isolate, receiver, INCLUDE_PROTOS,
ENUMERABLE_STRINGS);
// Test if we have an enum cache for {receiver}.
if (!accumulator.is_receiver_simple_enum()) {
if (!receiver->IsSimpleEnum()) {
Handle<FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION(isolate, keys, accumulator.GetKeys(KEEP_NUMBERS),
HeapObject);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, keys,
JSReceiver::GetKeys(receiver, INCLUDE_PROTOS, ENUMERABLE_STRINGS),
HeapObject);
// Test again, since cache may have been built by GetKeys() calls above.
if (!accumulator.is_receiver_simple_enum()) return keys;
if (!receiver->IsSimpleEnum()) return keys;
}
return handle(receiver->map(), isolate);
}
@ -38,19 +36,10 @@ MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) {
MaybeHandle<Object> Filter(Handle<JSReceiver> receiver, Handle<Object> key) {
Isolate* const isolate = receiver->GetIsolate();
// TODO(turbofan): Fast case for array indices.
Handle<Name> name;
ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key),
Object);
// Directly check for elements if the key is a smi and avoid a conversion
// roundtrip (Number -> Name -> Number).
if (key->IsNumber() && receiver->map()->OnlyHasSimpleProperties()) {
Handle<JSObject> object = Handle<JSObject>::cast(receiver);
ElementsAccessor* accessor = object->GetElementsAccessor();
DCHECK_LT(key->Number(), kMaxUInt32);
if (accessor->HasElement(object, key->Number(), ONLY_ENUMERABLE)) {
return name;
}
}
Maybe<bool> result = JSReceiver::HasProperty(receiver, name);
MAYBE_RETURN_NULL(result);
if (result.FromJust()) return name;

View File

@ -120,23 +120,7 @@ for (i=0 ; i < 3; ++i) {
assertEquals("undefined", typeof y[0], "y[0]");
}
(function testLargeElementKeys() {
// Key out of SMI range but well within safe double representaion.
var large_key = 2147483650;
var o = [];
// Trigger dictionary elements with HeapNumber keys.
o[large_key] = 0;
o[large_key+1] = 1;
o[large_key+2] = 2;
o[large_key+3] = 3;
var keys = [];
for (var k in o) {
keys.push(k);
}
assertEquals(["2147483650", "2147483651", "2147483652", "2147483653"], keys);
})();
(function testLargeElementKeysWithProto() {
(function() {
var large_key = 2147483650;
var o = {__proto__: {}};
o[large_key] = 1;
@ -147,17 +131,3 @@ for (i=0 ; i < 3; ++i) {
}
assertEquals(["2147483650"], keys);
})();
(function testNonEnumerableArgumentsIndex() {
Object.defineProperty(arguments, 0, {enumerable:false});
for (var k in arguments) {
assertUnreachable();
}
})();
(function testNonEnumerableSloppyArgumentsIndex(a) {
Object.defineProperty(arguments, 0, {enumerable:false});
for (var k in arguments) {
assertUnreachable();
}
})(true);

View File

@ -957,8 +957,8 @@
'../../src/isolate.h',
'../../src/json-parser.h',
'../../src/json-stringifier.h',
'../../src/keys.h',
'../../src/keys.cc',
'../../src/key-accumulator.h',
'../../src/key-accumulator.cc',
'../../src/layout-descriptor-inl.h',
'../../src/layout-descriptor.cc',
'../../src/layout-descriptor.h',