Commit c043a7ee authored by cbruni's avatar cbruni Committed by Commit bot

[runtime] Use std::vector in KeyAccumulator

LOG=N
BUG=chromium:545503

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

Cr-Commit-Position: refs/heads/master@{#31557}
parent b694266b
...@@ -7530,7 +7530,7 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, ...@@ -7530,7 +7530,7 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
KeyAccumulator::~KeyAccumulator() { KeyAccumulator::~KeyAccumulator() {
for (int i = 0; i < elements_.length(); i++) { for (size_t i = 0; i < elements_.size(); i++) {
delete elements_[i]; delete elements_[i];
} }
} }
...@@ -7551,7 +7551,7 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { ...@@ -7551,7 +7551,7 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_);
int index = 0; int index = 0;
int properties_index = 0; int properties_index = 0;
for (int level = 0; level < levelLengths_.length(); level++) { for (size_t level = 0; level < levelLengths_.size(); level++) {
int num_total = levelLengths_[level]; int num_total = levelLengths_[level];
int num_elements = 0; int num_elements = 0;
if (num_total < 0) { if (num_total < 0) {
...@@ -7559,9 +7559,9 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { ...@@ -7559,9 +7559,9 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
// proxy, hence we skip the integer keys in |elements_| since proxies // proxy, hence we skip the integer keys in |elements_| since proxies
// define the complete ordering. // define the complete ordering.
num_total = -num_total; num_total = -num_total;
} else if (level < elements_.length()) { } else if (level < elements_.size()) {
List<uint32_t>* elements = elements_[level]; std::vector<uint32_t>* elements = elements_[level];
num_elements = elements->length(); num_elements = static_cast<int>(elements->size());
for (int i = 0; i < num_elements; i++) { for (int i = 0; i < num_elements; i++) {
Handle<Object> key; Handle<Object> key;
if (convert == KEEP_NUMBERS) { if (convert == KEEP_NUMBERS) {
...@@ -7582,6 +7582,7 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { ...@@ -7582,6 +7582,7 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
properties_index++; properties_index++;
} }
} }
DCHECK_EQ(index, length_); DCHECK_EQ(index, length_);
return result; return result;
} }
...@@ -7589,22 +7590,8 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { ...@@ -7589,22 +7590,8 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
namespace { namespace {
class FindKey { bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) {
public: return std::binary_search(sub_elements->begin(), sub_elements->end(), key);
explicit FindKey(uint32_t key) : key_(key) {}
int operator()(uint32_t* entry) {
if (*entry == key_) return 0;
return *entry < key_ ? -1 : 1;
}
private:
uint32_t key_;
};
bool AccumulatorHasKey(List<uint32_t>* sub_elements, uint32_t key) {
int index = SortedListBSearch(*sub_elements, FindKey(key));
return index != -1;
} }
} // namespace } // namespace
...@@ -7612,12 +7599,14 @@ bool AccumulatorHasKey(List<uint32_t>* sub_elements, uint32_t key) { ...@@ -7612,12 +7599,14 @@ bool AccumulatorHasKey(List<uint32_t>* sub_elements, uint32_t key) {
bool KeyAccumulator::AddKey(uint32_t key) { bool KeyAccumulator::AddKey(uint32_t key) {
// Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy).
// We mark proxy-levels with a negative length
DCHECK_LE(0, levelLength_); DCHECK_LE(0, levelLength_);
int lookup_limit = elements_.length(); // Binary search over all but the last level. The last one might not be
for (int i = 0; i < lookup_limit; i++) { // sorted yet.
if (AccumulatorHasKey(elements_[i], key)) return false; for (size_t i = 1; i < elements_.size(); i++) {
if (AccumulatorHasKey(elements_[i - 1], key)) return false;
} }
elements_[lookup_limit - 1]->Add(key); elements_.back()->push_back(key);
length_++; length_++;
levelLength_++; levelLength_++;
return true; return true;
...@@ -7711,32 +7700,43 @@ void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) { ...@@ -7711,32 +7700,43 @@ void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) {
} }
namespace { void KeyAccumulator::AddElementKeysFromInterceptor(
Handle<JSObject> array_like) {
// Used for sorting indices in a List<uint32_t>. AddKeys(array_like, CONVERT_TO_ARRAY_INDEX);
int compareUInt32(const uint32_t* ap, const uint32_t* bp) { // The interceptor might introduce duplicates for the current level, since
uint32_t a = *ap; // these keys get added after the objects's normal element keys.
uint32_t b = *bp; SortCurrentElementsListRemoveDuplicates();
return (a == b) ? 0 : (a < b) ? -1 : 1;
} }
} // namespace void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() {
// Sort and remove duplciated from the current elements level and adjust
// the lengths accordingly.
auto last_level = elements_.back();
size_t nof_removed_keys = last_level->size();
std::sort(last_level->begin(), last_level->end());
last_level->erase(std::unique(last_level->begin(), last_level->end()),
last_level->end());
// Adjust total length / level length by the number of removed duplicates
nof_removed_keys -= last_level->size();
levelLength_ -= static_cast<int>(nof_removed_keys);
length_ -= static_cast<int>(nof_removed_keys);
}
void KeyAccumulator::SortCurrentElementsList() { void KeyAccumulator::SortCurrentElementsList() {
if (elements_.length() == 0) return; if (elements_.empty()) return;
List<uint32_t>* element_keys = elements_[elements_.length() - 1]; auto element_keys = elements_.back();
element_keys->Sort(&compareUInt32); std::sort(element_keys->begin(), element_keys->end());
} }
void KeyAccumulator::NextPrototype() { void KeyAccumulator::NextPrototype() {
// Store the protoLength on the first call of this method. // Store the protoLength on the first call of this method.
if (!elements_.is_empty()) { if (!elements_.empty()) {
levelLengths_.Add(levelLength_); levelLengths_.push_back(levelLength_);
} }
elements_.Add(new List<uint32_t>()); elements_.push_back(new std::vector<uint32_t>());
levelLength_ = 0; levelLength_ = 0;
} }
...@@ -7750,7 +7750,6 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, ...@@ -7750,7 +7750,6 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
KeyAccumulator accumulator(isolate, filter); KeyAccumulator accumulator(isolate, filter);
Handle<JSFunction> arguments_function( Handle<JSFunction> arguments_function(
JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
PrototypeIterator::WhereToEnd end = type == OWN_ONLY PrototypeIterator::WhereToEnd end = type == OWN_ONLY
? PrototypeIterator::END_AT_NON_HIDDEN ? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL; : PrototypeIterator::END_AT_NULL;
...@@ -7795,7 +7794,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, ...@@ -7795,7 +7794,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
Handle<JSObject> result; Handle<JSObject> result;
if (JSObject::GetKeysForIndexedInterceptor(current, object) if (JSObject::GetKeysForIndexedInterceptor(current, object)
.ToHandle(&result)) { .ToHandle(&result)) {
accumulator.AddKeys(result, CONVERT_TO_ARRAY_INDEX); accumulator.AddElementKeysFromInterceptor(result);
} }
} }
......
...@@ -10801,7 +10801,7 @@ class KeyAccumulator final BASE_EMBEDDED { ...@@ -10801,7 +10801,7 @@ class KeyAccumulator final BASE_EMBEDDED {
public: public:
explicit KeyAccumulator(Isolate* isolate, explicit KeyAccumulator(Isolate* isolate,
KeyFilter filter = KeyFilter::SKIP_SYMBOLS) KeyFilter filter = KeyFilter::SKIP_SYMBOLS)
: isolate_(isolate), filter_(filter), length_(0), levelLength_(0) {} : isolate_(isolate), filter_(filter) {}
~KeyAccumulator(); ~KeyAccumulator();
bool AddKey(uint32_t key); bool AddKey(uint32_t key);
...@@ -10812,11 +10812,13 @@ class KeyAccumulator final BASE_EMBEDDED { ...@@ -10812,11 +10812,13 @@ class KeyAccumulator final BASE_EMBEDDED {
void AddKeys(Handle<JSObject> array, void AddKeys(Handle<JSObject> array,
AddKeyConversion convert = DO_NOT_CONVERT); AddKeyConversion convert = DO_NOT_CONVERT);
void AddKeysFromProxy(Handle<JSObject> array); void AddKeysFromProxy(Handle<JSObject> array);
void AddElementKeysFromInterceptor(Handle<JSObject> array);
// Jump to the next level, pushing the current |levelLength_| to // Jump to the next level, pushing the current |levelLength_| to
// |levelLengths_| and adding a new list to |elements_|. // |levelLengths_| and adding a new list to |elements_|.
void NextPrototype(); void NextPrototype();
// Sort the integer indices in the last list in |elements_| // Sort the integer indices in the last list in |elements_|
void SortCurrentElementsList(); void SortCurrentElementsList();
void SortCurrentElementsListRemoveDuplicates();
Handle<FixedArray> GetKeys(GetKeysConversion convert = KEEP_NUMBERS); Handle<FixedArray> GetKeys(GetKeysConversion convert = KEEP_NUMBERS);
...@@ -10824,17 +10826,17 @@ class KeyAccumulator final BASE_EMBEDDED { ...@@ -10824,17 +10826,17 @@ class KeyAccumulator final BASE_EMBEDDED {
Isolate* isolate_; Isolate* isolate_;
KeyFilter filter_; KeyFilter filter_;
// |elements_| contains the sorted element keys (indices) per level. // |elements_| contains the sorted element keys (indices) per level.
List<List<uint32_t>*> elements_; std::vector<std::vector<uint32_t>*> elements_;
// |protoLengths_| contains the total number of keys (elements + properties) // |protoLengths_| contains the total number of keys (elements + properties)
// per level. Negative values mark counts for a level with keys from a proxy. // per level. Negative values mark counts for a level with keys from a proxy.
List<int> levelLengths_; std::vector<int> levelLengths_;
// |properties_| contains the property keys per level in insertion order. // |properties_| contains the property keys per level in insertion order.
Handle<OrderedHashSet> properties_; Handle<OrderedHashSet> properties_;
// |length_| keeps track of the total number of all element and property keys. // |length_| keeps track of the total number of all element and property keys.
int length_; int length_ = 0;
// |levelLength_| keeps track of the total number of keys // |levelLength_| keeps track of the total number of keys
// (elements + properties) in the current level. // (elements + properties) in the current level.
int levelLength_; int levelLength_ = 0;
DISALLOW_COPY_AND_ASSIGN(KeyAccumulator); DISALLOW_COPY_AND_ASSIGN(KeyAccumulator);
}; };
......
...@@ -207,7 +207,6 @@ RUNTIME_FUNCTION(Runtime_GetArrayKeys) { ...@@ -207,7 +207,6 @@ RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
KeyAccumulator accumulator(isolate); KeyAccumulator accumulator(isolate);
// No need to separate protoype levels since we only get numbers/element keys // No need to separate protoype levels since we only get numbers/element keys
accumulator.NextPrototype();
for (PrototypeIterator iter(isolate, array, for (PrototypeIterator iter(isolate, array,
PrototypeIterator::START_AT_RECEIVER); PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(); iter.Advance()) { !iter.IsAtEnd(); iter.Advance()) {
...@@ -218,6 +217,7 @@ RUNTIME_FUNCTION(Runtime_GetArrayKeys) { ...@@ -218,6 +217,7 @@ RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
// collecting keys in that case. // collecting keys in that case.
return *isolate->factory()->NewNumberFromUint(length); return *isolate->factory()->NewNumberFromUint(length);
} }
accumulator.NextPrototype();
Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
JSObject::CollectOwnElementKeys(current, &accumulator, NONE); JSObject::CollectOwnElementKeys(current, &accumulator, NONE);
} }
......
...@@ -2010,16 +2010,14 @@ THREADED_TEST(Enumerators) { ...@@ -2010,16 +2010,14 @@ THREADED_TEST(Enumerators) {
// This order is not mandated by the spec, so this test is just // This order is not mandated by the spec, so this test is just
// documenting our behavior. // documenting our behavior.
CHECK_EQ(17u, result->Length()); CHECK_EQ(17u, result->Length());
// Indexed properties in numerical order. // Indexed properties + indexed interceptor properties in numerical order.
CHECK(v8_str("5")->Equals(result->Get(v8::Integer::New(isolate, 0)))); CHECK(v8_str("0")->Equals(result->Get(v8::Integer::New(isolate, 0))));
CHECK(v8_str("10")->Equals(result->Get(v8::Integer::New(isolate, 1)))); CHECK(v8_str("1")->Equals(result->Get(v8::Integer::New(isolate, 1))));
CHECK(v8_str("140000")->Equals(result->Get(v8::Integer::New(isolate, 2)))); CHECK(v8_str("5")->Equals(result->Get(v8::Integer::New(isolate, 2))));
CHECK(v8_str("10")->Equals(result->Get(v8::Integer::New(isolate, 3))));
CHECK(v8_str("140000")->Equals(result->Get(v8::Integer::New(isolate, 4))));
CHECK( CHECK(
v8_str("4294967294")->Equals(result->Get(v8::Integer::New(isolate, 3)))); v8_str("4294967294")->Equals(result->Get(v8::Integer::New(isolate, 5))));
// Indexed interceptor properties in the order they are returned
// from the enumerator interceptor.
CHECK(v8_str("0")->Equals(result->Get(v8::Integer::New(isolate, 4))));
CHECK(v8_str("1")->Equals(result->Get(v8::Integer::New(isolate, 5))));
// Named properties in insertion order. // Named properties in insertion order.
CHECK(v8_str("a")->Equals(result->Get(v8::Integer::New(isolate, 6)))); CHECK(v8_str("a")->Equals(result->Get(v8::Integer::New(isolate, 6))));
CHECK(v8_str("b")->Equals(result->Get(v8::Integer::New(isolate, 7)))); CHECK(v8_str("b")->Equals(result->Get(v8::Integer::New(isolate, 7))));
......
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