| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/objects.h" | 5 #include "src/objects.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <iomanip> | 8 #include <iomanip> |
| 9 #include <sstream> | 9 #include <sstream> |
| 10 | 10 |
| 11 #include "src/accessors.h" | 11 #include "src/accessors.h" |
| 12 #include "src/allocation-site-scopes.h" | 12 #include "src/allocation-site-scopes.h" |
| 13 #include "src/api.h" | 13 #include "src/api.h" |
| 14 #include "src/arguments.h" | 14 #include "src/arguments.h" |
| 15 #include "src/base/bits.h" | 15 #include "src/base/bits.h" |
| 16 #include "src/base/utils/random-number-generator.h" | 16 #include "src/base/utils/random-number-generator.h" |
| 17 #include "src/bootstrapper.h" | 17 #include "src/bootstrapper.h" |
| 18 #include "src/code-stubs.h" | 18 #include "src/code-stubs.h" |
| 19 #include "src/codegen.h" | 19 #include "src/codegen.h" |
| 20 #include "src/compilation-dependencies.h" | 20 #include "src/compilation-dependencies.h" |
| 21 #include "src/compiler.h" | 21 #include "src/compiler.h" |
| 22 #include "src/date.h" | 22 #include "src/date.h" |
| 23 #include "src/debug/debug.h" | 23 #include "src/debug/debug.h" |
| 24 #include "src/deoptimizer.h" | 24 #include "src/deoptimizer.h" |
| 25 #include "src/elements.h" | 25 #include "src/elements.h" |
| 26 #include "src/execution.h" | 26 #include "src/execution.h" |
| 27 #include "src/field-index.h" |
| 27 #include "src/field-index-inl.h" | 28 #include "src/field-index-inl.h" |
| 28 #include "src/field-index.h" | |
| 29 #include "src/full-codegen/full-codegen.h" | 29 #include "src/full-codegen/full-codegen.h" |
| 30 #include "src/hydrogen.h" | 30 #include "src/hydrogen.h" |
| 31 #include "src/ic/ic.h" | 31 #include "src/ic/ic.h" |
| 32 #include "src/interpreter/bytecodes.h" | 32 #include "src/interpreter/bytecodes.h" |
| 33 #include "src/isolate-inl.h" | 33 #include "src/isolate-inl.h" |
| 34 #include "src/list.h" |
| 34 #include "src/log.h" | 35 #include "src/log.h" |
| 35 #include "src/lookup.h" | 36 #include "src/lookup.h" |
| 36 #include "src/macro-assembler.h" | 37 #include "src/macro-assembler.h" |
| 37 #include "src/messages.h" | 38 #include "src/messages.h" |
| 38 #include "src/objects-inl.h" | 39 #include "src/objects-inl.h" |
| 39 #include "src/profiler/cpu-profiler.h" | 40 #include "src/profiler/cpu-profiler.h" |
| 40 #include "src/property-descriptor.h" | 41 #include "src/property-descriptor.h" |
| 41 #include "src/prototype.h" | 42 #include "src/prototype.h" |
| 42 #include "src/safepoint-table.h" | 43 #include "src/safepoint-table.h" |
| 43 #include "src/string-builder.h" | 44 #include "src/string-builder.h" |
| (...skipping 7278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7322 if (current->IsAccessCheckNeeded()) return false; | 7323 if (current->IsAccessCheckNeeded()) return false; |
| 7323 DCHECK(!current->HasNamedInterceptor()); | 7324 DCHECK(!current->HasNamedInterceptor()); |
| 7324 DCHECK(!current->HasIndexedInterceptor()); | 7325 DCHECK(!current->HasIndexedInterceptor()); |
| 7325 if (current->NumberOfEnumElements() > 0) return false; | 7326 if (current->NumberOfEnumElements() > 0) return false; |
| 7326 if (current != this && enum_length != 0) return false; | 7327 if (current != this && enum_length != 0) return false; |
| 7327 } | 7328 } |
| 7328 return true; | 7329 return true; |
| 7329 } | 7330 } |
| 7330 | 7331 |
| 7331 | 7332 |
| 7332 static bool FilterKey(Object* key, PropertyAttributes filter) { | |
| 7333 if ((filter & SYMBOLIC) && key->IsSymbol()) { | |
| 7334 return true; | |
| 7335 } | |
| 7336 | |
| 7337 if ((filter & PRIVATE_SYMBOL) && | |
| 7338 key->IsSymbol() && Symbol::cast(key)->is_private()) { | |
| 7339 return true; | |
| 7340 } | |
| 7341 | |
| 7342 if ((filter & STRING) && !key->IsSymbol()) { | |
| 7343 return true; | |
| 7344 } | |
| 7345 | |
| 7346 return false; | |
| 7347 } | |
| 7348 | |
| 7349 | |
| 7350 int Map::NumberOfDescribedProperties(DescriptorFlag which, | 7333 int Map::NumberOfDescribedProperties(DescriptorFlag which, |
| 7351 PropertyAttributes filter) { | 7334 PropertyAttributes filter) { |
| 7352 int result = 0; | 7335 int result = 0; |
| 7353 DescriptorArray* descs = instance_descriptors(); | 7336 DescriptorArray* descs = instance_descriptors(); |
| 7354 int limit = which == ALL_DESCRIPTORS | 7337 int limit = which == ALL_DESCRIPTORS |
| 7355 ? descs->number_of_descriptors() | 7338 ? descs->number_of_descriptors() |
| 7356 : NumberOfOwnDescriptors(); | 7339 : NumberOfOwnDescriptors(); |
| 7357 for (int i = 0; i < limit; i++) { | 7340 for (int i = 0; i < limit; i++) { |
| 7358 if ((descs->GetDetails(i).attributes() & filter) == 0 && | 7341 if ((descs->GetDetails(i).attributes() & filter) == 0 && |
| 7359 !FilterKey(descs->GetKey(i), filter)) { | 7342 !descs->GetKey(i)->FilterKey(filter)) { |
| 7360 result++; | 7343 result++; |
| 7361 } | 7344 } |
| 7362 } | 7345 } |
| 7363 return result; | 7346 return result; |
| 7364 } | 7347 } |
| 7365 | 7348 |
| 7366 | 7349 |
| 7367 int Map::NextFreePropertyIndex() { | 7350 int Map::NextFreePropertyIndex() { |
| 7368 int free_index = 0; | 7351 int free_index = 0; |
| 7369 int number_of_own_descriptors = NumberOfOwnDescriptors(); | 7352 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7500 if (length == 0) { | 7483 if (length == 0) { |
| 7501 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 7484 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
| 7502 } | 7485 } |
| 7503 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 7486 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| 7504 dictionary->CopyEnumKeysTo(*storage); | 7487 dictionary->CopyEnumKeysTo(*storage); |
| 7505 return storage; | 7488 return storage; |
| 7506 } | 7489 } |
| 7507 } | 7490 } |
| 7508 | 7491 |
| 7509 | 7492 |
| 7510 Handle<FixedArray> KeyAccumulator::GetKeys() { | 7493 KeyAccumulator::~KeyAccumulator() { |
| 7494 for (int i = 0; i < elements_.length(); i++) { |
| 7495 delete elements_[i]; |
| 7496 } |
| 7497 } |
| 7498 |
| 7499 |
| 7500 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
| 7511 if (length_ == 0) { | 7501 if (length_ == 0) { |
| 7512 return isolate_->factory()->empty_fixed_array(); | 7502 return isolate_->factory()->empty_fixed_array(); |
| 7513 } | 7503 } |
| 7514 if (set_.is_null()) { | 7504 // Make sure we have all the lengths collected. |
| 7515 keys_->Shrink(length_); | 7505 NextPrototype(); |
| 7516 return keys_; | 7506 |
| 7517 } | 7507 // Assemble the result array by first adding the element keys and then |
| 7518 // copy over results from set_ | 7508 // the property keys. We use the total number of keys per level in |
| 7509 // |protoLengths_| and the available element keys in the corresponding bucket |
| 7510 // in |elements_| to deduce the number of keys to take from the |properties_| |
| 7511 // set. |
| 7519 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); | 7512 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); |
| 7520 for (int i = 0; i < length_; i++) { | 7513 int index = 0; |
| 7521 result->set(i, set_->KeyAt(i)); | 7514 int properties_index = 0; |
| 7522 } | 7515 for (int level = 0; level < levelLengths_.length(); level++) { |
| 7516 int num_total = levelLengths_[level]; |
| 7517 int num_elements = 0; |
| 7518 if (num_total < 0) { |
| 7519 // If the total is negative, the current level contains properties from a |
| 7520 // proxy, hence we skip the integer keys in |elements_| since proxies |
| 7521 // define the complete ordering. |
| 7522 num_total = -num_total; |
| 7523 } else if (level < elements_.length()) { |
| 7524 List<uint32_t>* elements = elements_[level]; |
| 7525 num_elements = elements->length(); |
| 7526 for (int i = 0; i < num_elements; i++) { |
| 7527 Handle<Object> key; |
| 7528 if (convert == KEEP_NUMBERS) { |
| 7529 key = isolate_->factory()->NewNumberFromUint(elements->at(i)); |
| 7530 } else { |
| 7531 key = isolate_->factory()->Uint32ToString(elements->at(i)); |
| 7532 } |
| 7533 result->set(index, *key); |
| 7534 index++; |
| 7535 } |
| 7536 } |
| 7537 // Add the property keys for this prototype level. |
| 7538 int num_properties = num_total - num_elements; |
| 7539 for (int i = 0; i < num_properties; i++) { |
| 7540 Object* key = properties_->KeyAt(properties_index); |
| 7541 result->set(index, key); |
| 7542 index++; |
| 7543 properties_index++; |
| 7544 } |
| 7545 } |
| 7546 DCHECK_EQ(index, length_); |
| 7523 return result; | 7547 return result; |
| 7524 } | 7548 } |
| 7525 | 7549 |
| 7526 | 7550 |
| 7527 void KeyAccumulator::AddKey(Handle<Object> key, int check_limit) { | 7551 namespace { |
| 7528 #ifdef ENABLE_SLOW_DCHECKS | 7552 |
| 7529 if (FLAG_enable_slow_asserts) { | 7553 class FindKey { |
| 7530 DCHECK(key->IsNumber() || key->IsName()); | 7554 public: |
| 7531 } | 7555 explicit FindKey(uint32_t key) : key_(key) {} |
| 7532 #endif | 7556 int operator()(uint32_t* entry) { |
| 7533 if (!set_.is_null()) { | 7557 if (*entry == key_) return 0; |
| 7534 set_ = OrderedHashSet::Add(set_, key); | 7558 return *entry < key_ ? -1 : 1; |
| 7535 length_ = set_->NumberOfElements(); | 7559 } |
| 7536 return; | 7560 |
| 7537 } | 7561 private: |
| 7538 // check if we already have the key in the case we are still using | 7562 uint32_t key_; |
| 7539 // the keys_ FixedArray | 7563 }; |
| 7540 check_limit = Min(check_limit, length_); | 7564 |
| 7541 for (int i = 0; i < check_limit; i++) { | 7565 |
| 7542 Object* current = keys_->get(i); | 7566 bool AccumulatorHasKey(List<uint32_t>* sub_elements, uint32_t key) { |
| 7543 if (current->KeyEquals(*key)) return; | 7567 int index = SortedListBSearch(*sub_elements, FindKey(key)); |
| 7544 } | 7568 return index != -1; |
| 7545 EnsureCapacity(length_); | 7569 } |
| 7546 keys_->set(length_, *key); | 7570 |
| 7571 } // namespace |
| 7572 |
| 7573 |
| 7574 bool KeyAccumulator::AddKey(uint32_t key) { |
| 7575 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). |
| 7576 DCHECK_LE(0, levelLength_); |
| 7577 int lookup_limit = elements_.length(); |
| 7578 for (int i = 0; i < lookup_limit; i++) { |
| 7579 if (AccumulatorHasKey(elements_[i], key)) return false; |
| 7580 } |
| 7581 elements_[lookup_limit - 1]->Add(key); |
| 7547 length_++; | 7582 length_++; |
| 7548 } | 7583 levelLength_++; |
| 7549 | 7584 return true; |
| 7550 | 7585 } |
| 7551 void KeyAccumulator::AddKeys(Handle<FixedArray> array, KeyFilter filter) { | 7586 |
| 7587 |
| 7588 bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { |
| 7589 return AddKey(handle(key, isolate_), convert); |
| 7590 } |
| 7591 |
| 7592 |
| 7593 bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| 7594 if (filter_ == SKIP_SYMBOLS && key->IsSymbol()) { |
| 7595 return false; |
| 7596 } |
| 7597 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). |
| 7598 DCHECK_LE(0, levelLength_); |
| 7599 // In some cases (e.g. proxies) we might get in String-converted ints which |
| 7600 // should be added to the elements list instead of the properties. For |
| 7601 // proxies we have to convert as well but also respect the original order. |
| 7602 // Therefore we add a converted key to both sides |
| 7603 if (convert == CONVERT_TO_ARRAY_INDEX || convert == PROXY_MAGIC) { |
| 7604 uint32_t index = 0; |
| 7605 int prev_length = length_; |
| 7606 int prev_proto = levelLength_; |
| 7607 bool was_array_index = false; |
| 7608 bool key_was_added = false; |
| 7609 if ((key->IsString() && Handle<String>::cast(key)->AsArrayIndex(&index)) || |
| 7610 key->ToArrayIndex(&index)) { |
| 7611 key_was_added = AddKey(index); |
| 7612 was_array_index = true; |
| 7613 if (convert == CONVERT_TO_ARRAY_INDEX) return key_was_added; |
| 7614 } |
| 7615 if (was_array_index && convert == PROXY_MAGIC) { |
| 7616 // If we had an array index (number) and it wasn't added, the key |
| 7617 // already existed before, hence we cannot add it to the properties |
| 7618 // keys as it would lead to duplicate entries. |
| 7619 if (!key_was_added) { |
| 7620 return false; |
| 7621 } |
| 7622 length_ = prev_length; |
| 7623 levelLength_ = prev_proto; |
| 7624 } |
| 7625 } |
| 7626 if (properties_.is_null()) { |
| 7627 properties_ = OrderedHashSet::Allocate(isolate_, 16); |
| 7628 } |
| 7629 // TODO(cbruni): remove this conversion once we throw the correct TypeError |
| 7630 // for non-string/symbol elements returned by proxies |
| 7631 if (convert == PROXY_MAGIC && key->IsNumber()) { |
| 7632 key = isolate_->factory()->NumberToString(key); |
| 7633 } |
| 7634 int prev_size = properties_->NumberOfElements(); |
| 7635 properties_ = OrderedHashSet::Add(properties_, key); |
| 7636 if (prev_size < properties_->NumberOfElements()) { |
| 7637 length_++; |
| 7638 levelLength_++; |
| 7639 } |
| 7640 return true; |
| 7641 } |
| 7642 |
| 7643 |
| 7644 void KeyAccumulator::AddKeys(Handle<FixedArray> array, |
| 7645 AddKeyConversion convert) { |
| 7552 int add_length = array->length(); | 7646 int add_length = array->length(); |
| 7553 if (add_length == 0) return; | 7647 if (add_length == 0) return; |
| 7554 if (keys_.is_null() && filter == INCLUDE_SYMBOLS) { | |
| 7555 keys_ = array; | |
| 7556 length_ = keys_->length(); | |
| 7557 return; | |
| 7558 } | |
| 7559 PrepareForComparisons(add_length); | |
| 7560 int previous_key_count = length_; | |
| 7561 for (int i = 0; i < add_length; i++) { | 7648 for (int i = 0; i < add_length; i++) { |
| 7562 Handle<Object> current(array->get(i), isolate_); | 7649 Handle<Object> current(array->get(i), isolate_); |
| 7563 if (filter == SKIP_SYMBOLS && current->IsSymbol()) continue; | 7650 AddKey(current); |
| 7564 AddKey(current, previous_key_count); | 7651 } |
| 7565 } | 7652 } |
| 7566 } | 7653 |
| 7567 | 7654 |
| 7568 | 7655 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, |
| 7569 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, KeyFilter filter) { | 7656 AddKeyConversion convert) { |
| 7570 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); | 7657 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); |
| 7571 ElementsAccessor* accessor = array_like->GetElementsAccessor(); | 7658 ElementsAccessor* accessor = array_like->GetElementsAccessor(); |
| 7572 accessor->AddElementsToKeyAccumulator(array_like, this, filter); | 7659 accessor->AddElementsToKeyAccumulator(array_like, this, convert); |
| 7573 } | 7660 } |
| 7574 | 7661 |
| 7575 | 7662 |
| 7576 void KeyAccumulator::PrepareForComparisons(int count) { | 7663 void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) { |
| 7577 // Depending on how many comparisons we do we should switch to the | 7664 // Proxies define a complete list of keys with no distinction of |
| 7578 // hash-table-based checks which have a one-time overhead for | 7665 // elements and properties, which breaks the normal assumption for the |
| 7579 // initializing but O(1) for HasKey checks. | 7666 // KeyAccumulator. |
| 7580 if (!set_.is_null()) return; | 7667 AddKeys(array_like, PROXY_MAGIC); |
| 7581 // These limits were obtained through evaluation of several microbenchmarks. | 7668 // Invert the current length to indicate a present proxy, so we can ignore |
| 7582 if (length_ * count < 100) return; | 7669 // element keys for this level. Otherwise we would not fully respect the order |
| 7583 // Don't use a set for few elements | 7670 // given by the proxy. |
| 7584 if (length_ < 100 && count < 20) return; | 7671 levelLength_ = -levelLength_; |
| 7585 set_ = OrderedHashSet::Allocate(isolate_, length_); | 7672 } |
| 7586 for (int i = 0; i < length_; i++) { | 7673 |
| 7587 Handle<Object> value(keys_->get(i), isolate_); | 7674 |
| 7588 set_ = OrderedHashSet::Add(set_, value); | 7675 namespace { |
| 7589 } | 7676 |
| 7590 } | 7677 // Used for sorting indices in a List<uint32_t>. |
| 7591 | 7678 int compareUInt32(const uint32_t* ap, const uint32_t* bp) { |
| 7592 | 7679 uint32_t a = *ap; |
| 7593 void KeyAccumulator::EnsureCapacity(int capacity) { | 7680 uint32_t b = *bp; |
| 7594 if (keys_.is_null() || keys_->length() <= capacity) { | 7681 return (a == b) ? 0 : (a < b) ? -1 : 1; |
| 7595 Grow(); | 7682 } |
| 7596 } | 7683 |
| 7597 } | 7684 |
| 7598 | 7685 } // namespace |
| 7599 | 7686 |
| 7600 void KeyAccumulator::Grow() { | 7687 |
| 7601 // The OrderedHashSet handles growing by itself. | 7688 void KeyAccumulator::SortCurrentElementsList() { |
| 7602 if (!set_.is_null()) return; | 7689 if (elements_.length() == 0) return; |
| 7603 // Otherwise, grow the internal keys_ FixedArray | 7690 List<uint32_t>* element_keys = elements_[elements_.length() - 1]; |
| 7604 int capacity = keys_.is_null() ? 16 : keys_->length() * 2 + 16; | 7691 element_keys->Sort(&compareUInt32); |
| 7605 Handle<FixedArray> new_keys = isolate_->factory()->NewFixedArray(capacity); | 7692 } |
| 7606 if (keys_.is_null()) { | 7693 |
| 7607 keys_ = new_keys; | 7694 |
| 7608 return; | 7695 void KeyAccumulator::NextPrototype() { |
| 7609 } | 7696 // Store the protoLength on the first call of this method. |
| 7610 int buffer_length = keys_->length(); | 7697 if (!elements_.is_empty()) { |
| 7611 { | 7698 levelLengths_.Add(levelLength_); |
| 7612 DisallowHeapAllocation no_gc; | 7699 } |
| 7613 WriteBarrierMode mode = new_keys->GetWriteBarrierMode(no_gc); | 7700 elements_.Add(new List<uint32_t>()); |
| 7614 for (int i = 0; i < buffer_length; i++) { | 7701 levelLength_ = 0; |
| 7615 new_keys->set(i, keys_->get(i), mode); | |
| 7616 } | |
| 7617 } | |
| 7618 keys_ = new_keys; | |
| 7619 } | 7702 } |
| 7620 | 7703 |
| 7621 | 7704 |
| 7622 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, | 7705 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
| 7623 KeyCollectionType type, | 7706 KeyCollectionType type, |
| 7624 KeyFilter filter) { | 7707 KeyFilter filter, |
| 7708 GetKeysConversion getConversion) { |
| 7625 USE(ContainsOnlyValidKeys); | 7709 USE(ContainsOnlyValidKeys); |
| 7626 Isolate* isolate = object->GetIsolate(); | 7710 Isolate* isolate = object->GetIsolate(); |
| 7627 KeyAccumulator accumulator(isolate); | 7711 KeyAccumulator accumulator(isolate, filter); |
| 7628 Handle<JSFunction> arguments_function( | 7712 Handle<JSFunction> arguments_function( |
| 7629 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | 7713 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
| 7630 | 7714 |
| 7631 PrototypeIterator::WhereToEnd end = type == OWN_ONLY | 7715 PrototypeIterator::WhereToEnd end = type == OWN_ONLY |
| 7632 ? PrototypeIterator::END_AT_NON_HIDDEN | 7716 ? PrototypeIterator::END_AT_NON_HIDDEN |
| 7633 : PrototypeIterator::END_AT_NULL; | 7717 : PrototypeIterator::END_AT_NULL; |
| 7634 // Only collect keys if access is permitted. | 7718 // Only collect keys if access is permitted. |
| 7635 for (PrototypeIterator iter(isolate, object, | 7719 for (PrototypeIterator iter(isolate, object, |
| 7636 PrototypeIterator::START_AT_RECEIVER); | 7720 PrototypeIterator::START_AT_RECEIVER); |
| 7637 !iter.IsAtEnd(end); iter.Advance()) { | 7721 !iter.IsAtEnd(end); iter.Advance()) { |
| 7722 accumulator.NextPrototype(); |
| 7638 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 7723 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
| 7639 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); | 7724 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); |
| 7640 Handle<Object> args[] = { proxy }; | 7725 Handle<Object> args[] = { proxy }; |
| 7641 Handle<Object> names; | 7726 Handle<Object> names; |
| 7642 ASSIGN_RETURN_ON_EXCEPTION( | 7727 ASSIGN_RETURN_ON_EXCEPTION( |
| 7643 isolate, names, | 7728 isolate, names, |
| 7644 Execution::Call(isolate, | 7729 Execution::Call(isolate, |
| 7645 isolate->proxy_enumerate(), | 7730 isolate->proxy_enumerate(), |
| 7646 object, | 7731 object, |
| 7647 arraysize(args), | 7732 arraysize(args), |
| 7648 args), | 7733 args), |
| 7649 FixedArray); | 7734 FixedArray); |
| 7650 accumulator.AddKeys(Handle<JSObject>::cast(names), filter); | 7735 accumulator.AddKeysFromProxy(Handle<JSObject>::cast(names)); |
| 7651 break; | 7736 break; |
| 7652 } | 7737 } |
| 7653 | 7738 |
| 7654 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); | 7739 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
| 7655 | 7740 |
| 7656 // Check access rights if required. | 7741 // Check access rights if required. |
| 7657 if (current->IsAccessCheckNeeded() && | 7742 if (current->IsAccessCheckNeeded() && |
| 7658 !isolate->MayAccess(handle(isolate->context()), current)) { | 7743 !isolate->MayAccess(handle(isolate->context()), current)) { |
| 7659 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | 7744 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
| 7660 isolate->ReportFailedAccessCheck(current); | 7745 isolate->ReportFailedAccessCheck(current); |
| 7661 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | 7746 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); |
| 7662 } | 7747 } |
| 7663 break; | 7748 break; |
| 7664 } | 7749 } |
| 7665 | 7750 |
| 7666 // Compute the element keys. | 7751 JSObject::CollectOwnElementKeys(current, &accumulator, |
| 7667 Handle<FixedArray> element_keys = | 7752 static_cast<PropertyAttributes>(DONT_ENUM)); |
| 7668 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); | |
| 7669 current->GetEnumElementKeys(*element_keys); | |
| 7670 accumulator.AddKeys(element_keys, filter); | |
| 7671 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | |
| 7672 | 7753 |
| 7673 // Add the element keys from the interceptor. | 7754 // Add the element keys from the interceptor. |
| 7674 if (current->HasIndexedInterceptor()) { | 7755 if (current->HasIndexedInterceptor()) { |
| 7675 Handle<JSObject> result; | 7756 Handle<JSObject> result; |
| 7676 if (JSObject::GetKeysForIndexedInterceptor( | 7757 if (JSObject::GetKeysForIndexedInterceptor(current, object) |
| 7677 current, object).ToHandle(&result)) { | 7758 .ToHandle(&result)) { |
| 7678 accumulator.AddKeys(result, filter); | 7759 accumulator.AddKeys(result, CONVERT_TO_ARRAY_INDEX); |
| 7679 } | 7760 } |
| 7680 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | |
| 7681 } | 7761 } |
| 7682 | 7762 |
| 7683 if (filter == SKIP_SYMBOLS) { | 7763 if (filter == SKIP_SYMBOLS) { |
| 7684 // We can cache the computed property keys if access checks are | 7764 // We can cache the computed property keys if access checks are |
| 7685 // not needed and no interceptors are involved. | 7765 // not needed and no interceptors are involved. |
| 7686 // | 7766 // |
| 7687 // We do not use the cache if the object has elements and | 7767 // We do not use the cache if the object has elements and |
| 7688 // therefore it does not make sense to cache the property names | 7768 // therefore it does not make sense to cache the property names |
| 7689 // for arguments objects. Arguments objects will always have | 7769 // for arguments objects. Arguments objects will always have |
| 7690 // elements. | 7770 // elements. |
| 7691 // Wrapped strings have elements, but don't have an elements | 7771 // Wrapped strings have elements, but don't have an elements |
| 7692 // array or dictionary. So the fast inline test for whether to | 7772 // array or dictionary. So the fast inline test for whether to |
| 7693 // use the cache says yes, so we should not create a cache. | 7773 // use the cache says yes, so we should not create a cache. |
| 7694 bool cache_enum_length = | 7774 bool cache_enum_length = |
| 7695 ((current->map()->GetConstructor() != *arguments_function) && | 7775 ((current->map()->GetConstructor() != *arguments_function) && |
| 7696 !current->IsJSValue() && !current->IsAccessCheckNeeded() && | 7776 !current->IsJSValue() && !current->IsAccessCheckNeeded() && |
| 7697 !current->HasNamedInterceptor() && | 7777 !current->HasNamedInterceptor() && |
| 7698 !current->HasIndexedInterceptor()); | 7778 !current->HasIndexedInterceptor()); |
| 7699 // Compute the property keys and cache them if possible. | 7779 // Compute the property keys and cache them if possible. |
| 7700 | |
| 7701 Handle<FixedArray> enum_keys = | 7780 Handle<FixedArray> enum_keys = |
| 7702 JSObject::GetEnumPropertyKeys(current, cache_enum_length); | 7781 JSObject::GetEnumPropertyKeys(current, cache_enum_length); |
| 7703 accumulator.AddKeys(enum_keys, filter); | 7782 accumulator.AddKeys(enum_keys); |
| 7704 } else { | 7783 } else { |
| 7705 DCHECK(filter == INCLUDE_SYMBOLS); | 7784 DCHECK(filter == INCLUDE_SYMBOLS); |
| 7706 PropertyAttributes attr_filter = | 7785 PropertyAttributes attr_filter = |
| 7707 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); | 7786 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); |
| 7708 Handle<FixedArray> property_keys = isolate->factory()->NewFixedArray( | 7787 JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter); |
| 7709 current->NumberOfOwnProperties(attr_filter)); | |
| 7710 current->GetOwnPropertyNames(*property_keys, 0, attr_filter); | |
| 7711 accumulator.AddKeys(property_keys, filter); | |
| 7712 } | 7788 } |
| 7713 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | |
| 7714 | 7789 |
| 7715 // Add the property keys from the interceptor. | 7790 // Add the property keys from the interceptor. |
| 7716 if (current->HasNamedInterceptor()) { | 7791 if (current->HasNamedInterceptor()) { |
| 7717 Handle<JSObject> result; | 7792 Handle<JSObject> result; |
| 7718 if (JSObject::GetKeysForNamedInterceptor( | 7793 if (JSObject::GetKeysForNamedInterceptor(current, object) |
| 7719 current, object).ToHandle(&result)) { | 7794 .ToHandle(&result)) { |
| 7720 accumulator.AddKeys(result, filter); | 7795 accumulator.AddKeys(result); |
| 7721 } | 7796 } |
| 7722 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | |
| 7723 } | 7797 } |
| 7724 } | 7798 } |
| 7725 | 7799 |
| 7726 Handle<FixedArray> keys = accumulator.GetKeys(); | 7800 Handle<FixedArray> keys = accumulator.GetKeys(getConversion); |
| 7727 DCHECK(ContainsOnlyValidKeys(keys)); | 7801 DCHECK(ContainsOnlyValidKeys(keys)); |
| 7728 return keys; | 7802 return keys; |
| 7729 } | 7803 } |
| 7730 | 7804 |
| 7731 | 7805 |
| 7732 bool Map::DictionaryElementsInPrototypeChainOnly() { | 7806 bool Map::DictionaryElementsInPrototypeChainOnly() { |
| 7733 if (IsDictionaryElementsKind(elements_kind())) { | 7807 if (IsDictionaryElementsKind(elements_kind())) { |
| 7734 return false; | 7808 return false; |
| 7735 } | 7809 } |
| 7736 | 7810 |
| (...skipping 6936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14673 // mirrors. | 14747 // mirrors. |
| 14674 int JSObject::GetOwnPropertyNames(FixedArray* storage, int index, | 14748 int JSObject::GetOwnPropertyNames(FixedArray* storage, int index, |
| 14675 PropertyAttributes filter) { | 14749 PropertyAttributes filter) { |
| 14676 DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index)); | 14750 DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index)); |
| 14677 if (HasFastProperties()) { | 14751 if (HasFastProperties()) { |
| 14678 int start_index = index; | 14752 int start_index = index; |
| 14679 int real_size = map()->NumberOfOwnDescriptors(); | 14753 int real_size = map()->NumberOfOwnDescriptors(); |
| 14680 DescriptorArray* descs = map()->instance_descriptors(); | 14754 DescriptorArray* descs = map()->instance_descriptors(); |
| 14681 for (int i = 0; i < real_size; i++) { | 14755 for (int i = 0; i < real_size; i++) { |
| 14682 if ((descs->GetDetails(i).attributes() & filter) == 0 && | 14756 if ((descs->GetDetails(i).attributes() & filter) == 0 && |
| 14683 !FilterKey(descs->GetKey(i), filter)) { | 14757 !descs->GetKey(i)->FilterKey(filter)) { |
| 14684 storage->set(index++, descs->GetKey(i)); | 14758 storage->set(index++, descs->GetKey(i)); |
| 14685 } | 14759 } |
| 14686 } | 14760 } |
| 14687 return index - start_index; | 14761 return index - start_index; |
| 14688 } else if (IsGlobalObject()) { | 14762 } else if (IsGlobalObject()) { |
| 14689 return global_dictionary()->CopyKeysTo(storage, index, filter, | 14763 return global_dictionary()->CopyKeysTo(storage, index, filter, |
| 14690 GlobalDictionary::UNSORTED); | 14764 GlobalDictionary::UNSORTED); |
| 14691 } else { | 14765 } else { |
| 14692 return property_dictionary()->CopyKeysTo(storage, index, filter, | 14766 return property_dictionary()->CopyKeysTo(storage, index, filter, |
| 14693 NameDictionary::UNSORTED); | 14767 NameDictionary::UNSORTED); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 14708 // Compute the number of enumerable elements. | 14782 // Compute the number of enumerable elements. |
| 14709 return GetOwnElementKeys(NULL, filter); | 14783 return GetOwnElementKeys(NULL, filter); |
| 14710 } | 14784 } |
| 14711 | 14785 |
| 14712 | 14786 |
| 14713 int JSObject::NumberOfEnumElements() { | 14787 int JSObject::NumberOfEnumElements() { |
| 14714 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM)); | 14788 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM)); |
| 14715 } | 14789 } |
| 14716 | 14790 |
| 14717 | 14791 |
| 14792 void JSObject::CollectOwnElementKeys(Handle<JSObject> object, |
| 14793 KeyAccumulator* keys, |
| 14794 PropertyAttributes filter) { |
| 14795 uint32_t string_keys = 0; |
| 14796 |
| 14797 // If this is a String wrapper, add the string indices first, |
| 14798 // as they're guaranteed to precede the elements in numerical order |
| 14799 // and ascending order is required by ECMA-262, 6th, 9.1.12. |
| 14800 if (object->IsJSValue()) { |
| 14801 Object* val = JSValue::cast(*object)->value(); |
| 14802 if (val->IsString()) { |
| 14803 String* str = String::cast(val); |
| 14804 string_keys = str->length(); |
| 14805 for (uint32_t i = 0; i < string_keys; i++) { |
| 14806 keys->AddKey(i); |
| 14807 } |
| 14808 } |
| 14809 } |
| 14810 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 14811 accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0); |
| 14812 } |
| 14813 |
| 14814 |
| 14718 int JSObject::GetOwnElementKeys(FixedArray* storage, | 14815 int JSObject::GetOwnElementKeys(FixedArray* storage, |
| 14719 PropertyAttributes filter) { | 14816 PropertyAttributes filter) { |
| 14720 int counter = 0; | 14817 int counter = 0; |
| 14721 | 14818 |
| 14722 // If this is a String wrapper, add the string indices first, | 14819 // If this is a String wrapper, add the string indices first, |
| 14723 // as they're guaranteed to preced the elements in numerical order | 14820 // as they're guaranteed to precede the elements in numerical order |
| 14724 // and ascending order is required by ECMA-262, 6th, 9.1.12. | 14821 // and ascending order is required by ECMA-262, 6th, 9.1.12. |
| 14725 if (IsJSValue()) { | 14822 if (IsJSValue()) { |
| 14726 Object* val = JSValue::cast(this)->value(); | 14823 Object* val = JSValue::cast(this)->value(); |
| 14727 if (val->IsString()) { | 14824 if (val->IsString()) { |
| 14728 String* str = String::cast(val); | 14825 String* str = String::cast(val); |
| 14729 if (storage) { | 14826 if (storage) { |
| 14730 for (int i = 0; i < str->length(); i++) { | 14827 for (int i = 0; i < str->length(); i++) { |
| 14731 storage->set(counter + i, Smi::FromInt(i)); | 14828 storage->set(counter + i, Smi::FromInt(i)); |
| 14732 } | 14829 } |
| 14733 } | 14830 } |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14838 } | 14935 } |
| 14839 break; | 14936 break; |
| 14840 } | 14937 } |
| 14841 } | 14938 } |
| 14842 | 14939 |
| 14843 DCHECK(!storage || storage->length() == counter); | 14940 DCHECK(!storage || storage->length() == counter); |
| 14844 return counter; | 14941 return counter; |
| 14845 } | 14942 } |
| 14846 | 14943 |
| 14847 | 14944 |
| 14848 int JSObject::GetEnumElementKeys(FixedArray* storage) { | |
| 14849 return GetOwnElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM)); | |
| 14850 } | |
| 14851 | |
| 14852 | |
| 14853 const char* Symbol::PrivateSymbolToName() const { | 14945 const char* Symbol::PrivateSymbolToName() const { |
| 14854 Heap* heap = GetIsolate()->heap(); | 14946 Heap* heap = GetIsolate()->heap(); |
| 14855 #define SYMBOL_CHECK_AND_PRINT(name) \ | 14947 #define SYMBOL_CHECK_AND_PRINT(name) \ |
| 14856 if (this == heap->name()) return #name; | 14948 if (this == heap->name()) return #name; |
| 14857 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) | 14949 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) |
| 14858 #undef SYMBOL_CHECK_AND_PRINT | 14950 #undef SYMBOL_CHECK_AND_PRINT |
| 14859 return "UNKNOWN"; | 14951 return "UNKNOWN"; |
| 14860 } | 14952 } |
| 14861 | 14953 |
| 14862 | 14954 |
| (...skipping 1503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16366 } | 16458 } |
| 16367 | 16459 |
| 16368 | 16460 |
| 16369 template <typename Derived, typename Shape, typename Key> | 16461 template <typename Derived, typename Shape, typename Key> |
| 16370 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes( | 16462 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes( |
| 16371 PropertyAttributes filter) { | 16463 PropertyAttributes filter) { |
| 16372 int capacity = this->Capacity(); | 16464 int capacity = this->Capacity(); |
| 16373 int result = 0; | 16465 int result = 0; |
| 16374 for (int i = 0; i < capacity; i++) { | 16466 for (int i = 0; i < capacity; i++) { |
| 16375 Object* k = this->KeyAt(i); | 16467 Object* k = this->KeyAt(i); |
| 16376 if (this->IsKey(k) && !FilterKey(k, filter)) { | 16468 if (this->IsKey(k) && !k->FilterKey(filter)) { |
| 16377 if (this->IsDeleted(i)) continue; | 16469 if (this->IsDeleted(i)) continue; |
| 16378 PropertyDetails details = this->DetailsAt(i); | 16470 PropertyDetails details = this->DetailsAt(i); |
| 16379 PropertyAttributes attr = details.attributes(); | 16471 PropertyAttributes attr = details.attributes(); |
| 16380 if ((attr & filter) == 0) result++; | 16472 if ((attr & filter) == 0) result++; |
| 16381 } | 16473 } |
| 16382 } | 16474 } |
| 16383 return result; | 16475 return result; |
| 16384 } | 16476 } |
| 16385 | 16477 |
| 16386 | 16478 |
| 16387 template <typename Derived, typename Shape, typename Key> | 16479 template <typename Derived, typename Shape, typename Key> |
| 16388 bool Dictionary<Derived, Shape, Key>::HasComplexElements() { | 16480 bool Dictionary<Derived, Shape, Key>::HasComplexElements() { |
| 16389 int capacity = this->Capacity(); | 16481 int capacity = this->Capacity(); |
| 16390 for (int i = 0; i < capacity; i++) { | 16482 for (int i = 0; i < capacity; i++) { |
| 16391 Object* k = this->KeyAt(i); | 16483 Object* k = this->KeyAt(i); |
| 16392 if (this->IsKey(k) && !FilterKey(k, NONE)) { | 16484 if (this->IsKey(k) && !k->FilterKey(NONE)) { |
| 16393 if (this->IsDeleted(i)) continue; | 16485 if (this->IsDeleted(i)) continue; |
| 16394 PropertyDetails details = this->DetailsAt(i); | 16486 PropertyDetails details = this->DetailsAt(i); |
| 16395 if (details.type() == ACCESSOR_CONSTANT) return true; | 16487 if (details.type() == ACCESSOR_CONSTANT) return true; |
| 16396 PropertyAttributes attr = details.attributes(); | 16488 PropertyAttributes attr = details.attributes(); |
| 16397 if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true; | 16489 if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true; |
| 16398 } | 16490 } |
| 16399 } | 16491 } |
| 16400 return false; | 16492 return false; |
| 16401 } | 16493 } |
| 16402 | 16494 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16441 | 16533 |
| 16442 template <typename Derived, typename Shape, typename Key> | 16534 template <typename Derived, typename Shape, typename Key> |
| 16443 int Dictionary<Derived, Shape, Key>::CopyKeysTo( | 16535 int Dictionary<Derived, Shape, Key>::CopyKeysTo( |
| 16444 FixedArray* storage, int index, PropertyAttributes filter, | 16536 FixedArray* storage, int index, PropertyAttributes filter, |
| 16445 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) { | 16537 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) { |
| 16446 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter)); | 16538 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter)); |
| 16447 int start_index = index; | 16539 int start_index = index; |
| 16448 int capacity = this->Capacity(); | 16540 int capacity = this->Capacity(); |
| 16449 for (int i = 0; i < capacity; i++) { | 16541 for (int i = 0; i < capacity; i++) { |
| 16450 Object* k = this->KeyAt(i); | 16542 Object* k = this->KeyAt(i); |
| 16451 if (this->IsKey(k) && !FilterKey(k, filter)) { | 16543 if (this->IsKey(k) && !k->FilterKey(filter)) { |
| 16452 if (this->IsDeleted(i)) continue; | 16544 if (this->IsDeleted(i)) continue; |
| 16453 PropertyDetails details = this->DetailsAt(i); | 16545 PropertyDetails details = this->DetailsAt(i); |
| 16454 PropertyAttributes attr = details.attributes(); | 16546 PropertyAttributes attr = details.attributes(); |
| 16455 if ((attr & filter) == 0) storage->set(index++, k); | 16547 if ((attr & filter) == 0) storage->set(index++, k); |
| 16456 } | 16548 } |
| 16457 } | 16549 } |
| 16458 if (sort_mode == Dictionary::SORTED) { | 16550 if (sort_mode == Dictionary::SORTED) { |
| 16459 storage->SortPairs(storage, index); | 16551 storage->SortPairs(storage, index); |
| 16460 } | 16552 } |
| 16461 DCHECK(storage->length() >= index); | 16553 DCHECK(storage->length() >= index); |
| (...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 17666 if (cell->value() != *new_value) { | 17758 if (cell->value() != *new_value) { |
| 17667 cell->set_value(*new_value); | 17759 cell->set_value(*new_value); |
| 17668 Isolate* isolate = cell->GetIsolate(); | 17760 Isolate* isolate = cell->GetIsolate(); |
| 17669 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17761 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
| 17670 isolate, DependentCode::kPropertyCellChangedGroup); | 17762 isolate, DependentCode::kPropertyCellChangedGroup); |
| 17671 } | 17763 } |
| 17672 } | 17764 } |
| 17673 | 17765 |
| 17674 } // namespace internal | 17766 } // namespace internal |
| 17675 } // namespace v8 | 17767 } // namespace v8 |
| OLD | NEW |