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

Side by Side Diff: src/keys.cc

Issue 1938413002: [keys] Moving property/keys related methods to KeyAccumulator in keys.cc (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: nits Created 4 years, 7 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 unified diff | Download patch
« no previous file with comments | « src/keys.h ('k') | src/messages.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/keys.h" 5 #include "src/keys.h"
6 6
7 #include "src/api-arguments.h"
7 #include "src/elements.h" 8 #include "src/elements.h"
8 #include "src/factory.h" 9 #include "src/factory.h"
10 #include "src/identity-map.h"
9 #include "src/isolate-inl.h" 11 #include "src/isolate-inl.h"
10 #include "src/objects-inl.h" 12 #include "src/objects-inl.h"
11 #include "src/property-descriptor.h" 13 #include "src/property-descriptor.h"
12 #include "src/prototype.h" 14 #include "src/prototype.h"
13 15
14 namespace v8 { 16 namespace v8 {
15 namespace internal { 17 namespace internal {
16 18
17 KeyAccumulator::~KeyAccumulator() { 19 KeyAccumulator::~KeyAccumulator() {
18 for (size_t i = 0; i < elements_.size(); i++) { 20 for (size_t i = 0; i < elements_.size(); i++) {
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 // Store the protoLength on the first call of this method. 307 // Store the protoLength on the first call of this method.
306 if (!elements_.empty()) { 308 if (!elements_.empty()) {
307 level_lengths_.push_back(level_string_length_); 309 level_lengths_.push_back(level_string_length_);
308 level_lengths_.push_back(level_symbol_length_); 310 level_lengths_.push_back(level_symbol_length_);
309 } 311 }
310 elements_.push_back(new std::vector<uint32_t>()); 312 elements_.push_back(new std::vector<uint32_t>());
311 level_string_length_ = 0; 313 level_string_length_ = 0;
312 level_symbol_length_ = 0; 314 level_symbol_length_ = 0;
313 } 315 }
314 316
317 Maybe<bool> KeyAccumulator::GetKeys_Internal(Handle<JSReceiver> receiver,
318 Handle<JSReceiver> object,
319 KeyCollectionType type) {
320 // Proxies have no hidden prototype and we should not trigger the
321 // [[GetPrototypeOf]] trap on the last iteration when using
322 // AdvanceFollowingProxies.
323 if (type == OWN_ONLY && object->IsJSProxy()) {
324 MAYBE_RETURN(
325 JSProxyOwnPropertyKeys(receiver, Handle<JSProxy>::cast(object)),
326 Nothing<bool>());
327 return Just(true);
328 }
329
330 PrototypeIterator::WhereToEnd end = type == OWN_ONLY
331 ? PrototypeIterator::END_AT_NON_HIDDEN
332 : PrototypeIterator::END_AT_NULL;
333 for (PrototypeIterator iter(isolate_, object,
334 PrototypeIterator::START_AT_RECEIVER, end);
335 !iter.IsAtEnd();) {
336 Handle<JSReceiver> current =
337 PrototypeIterator::GetCurrent<JSReceiver>(iter);
338 Maybe<bool> result = Just(false); // Dummy initialization.
339 if (current->IsJSProxy()) {
340 result = JSProxyOwnPropertyKeys(receiver, Handle<JSProxy>::cast(current));
341 } else {
342 DCHECK(current->IsJSObject());
343 result =
344 GetKeysFromJSObject(receiver, Handle<JSObject>::cast(current), type);
345 }
346 MAYBE_RETURN(result, Nothing<bool>());
347 if (!result.FromJust()) break; // |false| means "stop iterating".
348 // Iterate through proxies but ignore access checks for the ALL_CAN_READ
349 // case on API objects for OWN_ONLY keys handled in GetKeysFromJSObject.
350 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
351 return Nothing<bool>();
352 }
353 }
354 return Just(true);
355 }
356
315 namespace { 357 namespace {
316 358
317 void TrySettingEmptyEnumCache(JSReceiver* object) { 359 void TrySettingEmptyEnumCache(JSReceiver* object) {
318 Map* map = object->map(); 360 Map* map = object->map();
319 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength()); 361 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
320 if (!map->OnlyHasSimpleProperties()) return; 362 if (!map->OnlyHasSimpleProperties()) return;
321 if (map->IsJSProxyMap()) return; 363 if (map->IsJSProxyMap()) return;
322 if (map->NumberOfOwnDescriptors() > 0) { 364 if (map->NumberOfOwnDescriptors() > 0) {
323 int number_of_enumerable_own_properties = 365 int number_of_enumerable_own_properties =
324 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS); 366 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 USE(first_non_empty_prototype); 398 USE(first_non_empty_prototype);
357 return; 399 return;
358 } 400 }
359 DCHECK(has_empty_prototype_); 401 DCHECK(has_empty_prototype_);
360 is_receiver_simple_enum_ = 402 is_receiver_simple_enum_ =
361 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && 403 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
362 !JSObject::cast(*receiver_)->HasEnumerableElements(); 404 !JSObject::cast(*receiver_)->HasEnumerableElements();
363 } 405 }
364 406
365 namespace { 407 namespace {
408 static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
409 Handle<FixedArray> array,
410 int length) {
411 DCHECK_LE(length, array->length());
412 if (array->length() == length) return array;
413 return isolate->factory()->CopyFixedArrayUpTo(array, length);
414 }
415
416 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
417 Handle<JSObject> object) {
418 Handle<Map> map(object->map());
419 bool cache_enum_length = map->OnlyHasSimpleProperties();
420
421 Handle<DescriptorArray> descs =
422 Handle<DescriptorArray>(map->instance_descriptors(), isolate);
423 int own_property_count = map->EnumLength();
424 // If the enum length of the given map is set to kInvalidEnumCache, this
425 // means that the map itself has never used the present enum cache. The
426 // first step to using the cache is to set the enum length of the map by
427 // counting the number of own descriptors that are ENUMERABLE_STRINGS.
428 if (own_property_count == kInvalidEnumCacheSentinel) {
429 own_property_count =
430 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
431 } else {
432 DCHECK(
433 own_property_count ==
434 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS));
435 }
436
437 if (descs->HasEnumCache()) {
438 Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
439 // In case the number of properties required in the enum are actually
440 // present, we can reuse the enum cache. Otherwise, this means that the
441 // enum cache was generated for a previous (smaller) version of the
442 // Descriptor Array. In that case we regenerate the enum cache.
443 if (own_property_count <= keys->length()) {
444 isolate->counters()->enum_cache_hits()->Increment();
445 if (cache_enum_length) map->SetEnumLength(own_property_count);
446 return ReduceFixedArrayTo(isolate, keys, own_property_count);
447 }
448 }
449
450 if (descs->IsEmpty()) {
451 isolate->counters()->enum_cache_hits()->Increment();
452 if (cache_enum_length) map->SetEnumLength(0);
453 return isolate->factory()->empty_fixed_array();
454 }
455
456 isolate->counters()->enum_cache_misses()->Increment();
457
458 Handle<FixedArray> storage =
459 isolate->factory()->NewFixedArray(own_property_count);
460 Handle<FixedArray> indices =
461 isolate->factory()->NewFixedArray(own_property_count);
462
463 int size = map->NumberOfOwnDescriptors();
464 int index = 0;
465
466 for (int i = 0; i < size; i++) {
467 PropertyDetails details = descs->GetDetails(i);
468 if (details.IsDontEnum()) continue;
469 Object* key = descs->GetKey(i);
470 if (key->IsSymbol()) continue;
471 storage->set(index, key);
472 if (!indices.is_null()) {
473 if (details.type() != DATA) {
474 indices = Handle<FixedArray>();
475 } else {
476 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
477 int load_by_field_index = field_index.GetLoadByFieldIndex();
478 indices->set(index, Smi::FromInt(load_by_field_index));
479 }
480 }
481 index++;
482 }
483 DCHECK(index == storage->length());
484
485 DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
486 if (cache_enum_length) {
487 map->SetEnumLength(own_property_count);
488 }
489 return storage;
490 }
366 491
367 template <bool fast_properties> 492 template <bool fast_properties>
368 Handle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, 493 Handle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
369 Handle<JSObject> object, 494 Handle<JSObject> object,
370 GetKeysConversion convert) { 495 GetKeysConversion convert) {
371 Handle<FixedArray> keys; 496 Handle<FixedArray> keys;
372 ElementsAccessor* accessor = object->GetElementsAccessor(); 497 ElementsAccessor* accessor = object->GetElementsAccessor();
373 if (fast_properties) { 498 if (fast_properties) {
374 keys = JSObject::GetFastEnumPropertyKeys(isolate, object); 499 keys = GetFastEnumPropertyKeys(isolate, object);
375 } else { 500 } else {
376 // TODO(cbruni): preallocate big enough array to also hold elements. 501 // TODO(cbruni): preallocate big enough array to also hold elements.
377 keys = JSObject::GetEnumPropertyKeys(object); 502 keys = KeyAccumulator::GetEnumPropertyKeys(isolate, object);
378 } 503 }
379 Handle<FixedArray> result = 504 Handle<FixedArray> result =
380 accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE); 505 accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE);
381 506
382 if (FLAG_trace_for_in_enumerate) { 507 if (FLAG_trace_for_in_enumerate) {
383 PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n", 508 PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n",
384 keys->length(), result->length() - keys->length()); 509 keys->length(), result->length() - keys->length());
385 } 510 }
386 return result; 511 return result;
387 } 512 }
388 513
389 MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache( 514 MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache(
390 Isolate* isolate, Handle<JSObject> object) { 515 Isolate* isolate, Handle<JSObject> object) {
391 // Uninitalized enum cache 516 // Uninitalized enum cache
392 Map* map = object->map(); 517 Map* map = object->map();
393 if (object->elements() != isolate->heap()->empty_fixed_array() || 518 if (object->elements() != isolate->heap()->empty_fixed_array() ||
394 object->elements() != isolate->heap()->empty_slow_element_dictionary()) { 519 object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
395 // Assume that there are elements. 520 // Assume that there are elements.
396 return MaybeHandle<FixedArray>(); 521 return MaybeHandle<FixedArray>();
397 } 522 }
398 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 523 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
399 if (number_of_own_descriptors == 0) { 524 if (number_of_own_descriptors == 0) {
400 map->SetEnumLength(0); 525 map->SetEnumLength(0);
401 return isolate->factory()->empty_fixed_array(); 526 return isolate->factory()->empty_fixed_array();
402 } 527 }
403 // We have no elements but possibly enumerable property keys, hence we can 528 // We have no elements but possibly enumerable property keys, hence we can
404 // directly initialize the enum cache. 529 // directly initialize the enum cache.
405 return JSObject::GetFastEnumPropertyKeys(isolate, object); 530 return GetFastEnumPropertyKeys(isolate, object);
406 } 531 }
407 532
408 bool OnlyHasSimpleProperties(Map* map) { 533 bool OnlyHasSimpleProperties(Map* map) {
409 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER; 534 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER;
410 } 535 }
411 536
412 } // namespace 537 } // namespace
413 538
414 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { 539 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) {
415 Handle<FixedArray> keys; 540 Handle<FixedArray> keys;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 // receiver. 579 // receiver.
455 return GetOwnKeysWithElements<true>(isolate_, object, convert); 580 return GetOwnKeysWithElements<true>(isolate_, object, convert);
456 } 581 }
457 582
458 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( 583 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
459 GetKeysConversion convert) { 584 GetKeysConversion convert) {
460 return JSReceiver::GetKeys(receiver_, type_, ENUMERABLE_STRINGS, KEEP_NUMBERS, 585 return JSReceiver::GetKeys(receiver_, type_, ENUMERABLE_STRINGS, KEEP_NUMBERS,
461 filter_proxy_keys_); 586 filter_proxy_keys_);
462 } 587 }
463 588
589 enum IndexedOrNamed { kIndexed, kNamed };
590
591 // Returns |true| on success, |nothing| on exception.
592 template <class Callback, IndexedOrNamed type>
593 static Maybe<bool> GetKeysFromInterceptor(Handle<JSReceiver> receiver,
594 Handle<JSObject> object,
595 KeyAccumulator* accumulator) {
596 Isolate* isolate = accumulator->isolate();
597 if (type == kIndexed) {
598 if (!object->HasIndexedInterceptor()) return Just(true);
599 } else {
600 if (!object->HasNamedInterceptor()) return Just(true);
601 }
602 Handle<InterceptorInfo> interceptor(type == kIndexed
603 ? object->GetIndexedInterceptor()
604 : object->GetNamedInterceptor(),
605 isolate);
606 if ((accumulator->filter() & ONLY_ALL_CAN_READ) &&
607 !interceptor->all_can_read()) {
608 return Just(true);
609 }
610 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
611 *object, Object::DONT_THROW);
612 Handle<JSObject> result;
613 if (!interceptor->enumerator()->IsUndefined()) {
614 Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
615 const char* log_tag = type == kIndexed ? "interceptor-indexed-enum"
616 : "interceptor-named-enum";
617 LOG(isolate, ApiObjectAccess(log_tag, *object));
618 result = args.Call(enum_fun);
619 }
620 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
621 if (result.is_null()) return Just(true);
622 DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
623 // The accumulator takes care of string/symbol filtering.
624 if (type == kIndexed) {
625 accumulator->AddElementKeysFromInterceptor(result);
626 } else {
627 accumulator->AddKeys(result, DO_NOT_CONVERT);
628 }
629 return Just(true);
630 }
631
632 void KeyAccumulator::CollectOwnElementKeys(Handle<JSObject> object) {
633 if (filter_ & SKIP_STRINGS) return;
634 ElementsAccessor* accessor = object->GetElementsAccessor();
635 accessor->CollectElementIndices(object, this, kMaxUInt32, filter_, 0);
636 }
637
638 void KeyAccumulator::CollectOwnPropertyNames(Handle<JSObject> object) {
639 if (object->HasFastProperties()) {
640 int real_size = object->map()->NumberOfOwnDescriptors();
641 Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
642 isolate_);
643 for (int i = 0; i < real_size; i++) {
644 PropertyDetails details = descs->GetDetails(i);
645 if ((details.attributes() & filter_) != 0) continue;
646 if (filter_ & ONLY_ALL_CAN_READ) {
647 if (details.kind() != kAccessor) continue;
648 Object* accessors = descs->GetValue(i);
649 if (!accessors->IsAccessorInfo()) continue;
650 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
651 }
652 Name* key = descs->GetKey(i);
653 if (key->FilterKey(filter_)) continue;
654 this->AddKey(key, DO_NOT_CONVERT);
655 }
656 } else if (object->IsJSGlobalObject()) {
657 GlobalDictionary::CollectKeysTo(
658 handle(object->global_dictionary(), isolate_), this, filter_);
659 } else {
660 NameDictionary::CollectKeysTo(
661 handle(object->property_dictionary(), isolate_), this, filter_);
662 }
663 }
664
665 // Returns |true| on success, |false| if prototype walking should be stopped,
666 // |nothing| if an exception was thrown.
667 Maybe<bool> KeyAccumulator::GetKeysFromJSObject(Handle<JSReceiver> receiver,
668 Handle<JSObject> object,
669 KeyCollectionType type) {
670 this->NextPrototype();
671 // Check access rights if required.
672 if (object->IsAccessCheckNeeded() &&
673 !isolate_->MayAccess(handle(isolate_->context()), object)) {
674 // The cross-origin spec says that [[Enumerate]] shall return an empty
675 // iterator when it doesn't have access...
676 if (type == INCLUDE_PROTOS) {
677 return Just(false);
678 }
679 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
680 DCHECK_EQ(OWN_ONLY, type);
681 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
682 }
683
684 this->CollectOwnElementKeys(object);
685
686 // Add the element keys from the interceptor.
687 Maybe<bool> success =
688 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
689 receiver, object, this);
690 MAYBE_RETURN(success, Nothing<bool>());
691
692 if (filter_ == ENUMERABLE_STRINGS) {
693 Handle<FixedArray> enum_keys =
694 KeyAccumulator::GetEnumPropertyKeys(isolate_, object);
695 this->AddKeys(enum_keys, DO_NOT_CONVERT);
696 } else {
697 this->CollectOwnPropertyNames(object);
698 }
699
700 // Add the property keys from the interceptor.
701 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
702 kNamed>(receiver, object, this);
703 MAYBE_RETURN(success, Nothing<bool>());
704 return Just(true);
705 }
706
707 // static
708 Handle<FixedArray> KeyAccumulator::GetEnumPropertyKeys(
709 Isolate* isolate, Handle<JSObject> object) {
710 if (object->HasFastProperties()) {
711 return GetFastEnumPropertyKeys(isolate, object);
712 } else if (object->IsJSGlobalObject()) {
713 Handle<GlobalDictionary> dictionary(object->global_dictionary(), isolate);
714 int length = dictionary->NumberOfEnumElements();
715 if (length == 0) {
716 return isolate->factory()->empty_fixed_array();
717 }
718 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
719 dictionary->CopyEnumKeysTo(*storage);
720 return storage;
721 } else {
722 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
723 int length = dictionary->NumberOfEnumElements();
724 if (length == 0) {
725 return isolate->factory()->empty_fixed_array();
726 }
727 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
728 dictionary->CopyEnumKeysTo(*storage);
729 return storage;
730 }
731 }
732
733 // ES6 9.5.12
734 // Returns |true| on success, |nothing| in case of exception.
735 Maybe<bool> KeyAccumulator::JSProxyOwnPropertyKeys(Handle<JSReceiver> receiver,
736 Handle<JSProxy> proxy) {
737 STACK_CHECK(isolate_, Nothing<bool>());
738 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
739 Handle<Object> handler(proxy->handler(), isolate_);
740 // 2. If handler is null, throw a TypeError exception.
741 // 3. Assert: Type(handler) is Object.
742 if (proxy->IsRevoked()) {
743 isolate_->Throw(*isolate_->factory()->NewTypeError(
744 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
745 return Nothing<bool>();
746 }
747 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
748 Handle<JSReceiver> target(proxy->target(), isolate_);
749 // 5. Let trap be ? GetMethod(handler, "ownKeys").
750 Handle<Object> trap;
751 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
752 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
753 isolate_->factory()->ownKeys_string()),
754 Nothing<bool>());
755 // 6. If trap is undefined, then
756 if (trap->IsUndefined()) {
757 // 6a. Return target.[[OwnPropertyKeys]]().
758 return this->GetKeys_Internal(receiver, target, OWN_ONLY);
759 }
760 // 7. Let trapResultArray be Call(trap, handler, «target»).
761 Handle<Object> trap_result_array;
762 Handle<Object> args[] = {target};
763 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
764 isolate_, trap_result_array,
765 Execution::Call(isolate_, trap, handler, arraysize(args), args),
766 Nothing<bool>());
767 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
768 // «String, Symbol»).
769 Handle<FixedArray> trap_result;
770 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
771 isolate_, trap_result,
772 Object::CreateListFromArrayLike(isolate_, trap_result_array,
773 ElementTypes::kStringAndSymbol),
774 Nothing<bool>());
775 // 9. Let extensibleTarget be ? IsExtensible(target).
776 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
777 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
778 bool extensible_target = maybe_extensible.FromJust();
779 // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
780 Handle<FixedArray> target_keys;
781 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys,
782 JSReceiver::OwnPropertyKeys(target),
783 Nothing<bool>());
784 // 11. (Assert)
785 // 12. Let targetConfigurableKeys be an empty List.
786 // To save memory, we're re-using target_keys and will modify it in-place.
787 Handle<FixedArray> target_configurable_keys = target_keys;
788 // 13. Let targetNonconfigurableKeys be an empty List.
789 Handle<FixedArray> target_nonconfigurable_keys =
790 isolate_->factory()->NewFixedArray(target_keys->length());
791 int nonconfigurable_keys_length = 0;
792 // 14. Repeat, for each element key of targetKeys:
793 for (int i = 0; i < target_keys->length(); ++i) {
794 // 14a. Let desc be ? target.[[GetOwnProperty]](key).
795 PropertyDescriptor desc;
796 Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
797 isolate_, target, handle(target_keys->get(i), isolate_), &desc);
798 MAYBE_RETURN(found, Nothing<bool>());
799 // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
800 if (found.FromJust() && !desc.configurable()) {
801 // 14b i. Append key as an element of targetNonconfigurableKeys.
802 target_nonconfigurable_keys->set(nonconfigurable_keys_length,
803 target_keys->get(i));
804 nonconfigurable_keys_length++;
805 // The key was moved, null it out in the original list.
806 target_keys->set(i, Smi::FromInt(0));
807 } else {
808 // 14c. Else,
809 // 14c i. Append key as an element of targetConfigurableKeys.
810 // (No-op, just keep it in |target_keys|.)
811 }
812 }
813 this->NextPrototype(); // Prepare for accumulating keys.
814 // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
815 // then:
816 if (extensible_target && nonconfigurable_keys_length == 0) {
817 // 15a. Return trapResult.
818 return this->AddKeysFromProxy(proxy, trap_result);
819 }
820 // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
821 Zone set_zone(isolate_->allocator());
822 const int kPresent = 1;
823 const int kGone = 0;
824 IdentityMap<int> unchecked_result_keys(isolate_->heap(), &set_zone);
825 int unchecked_result_keys_size = 0;
826 for (int i = 0; i < trap_result->length(); ++i) {
827 DCHECK(trap_result->get(i)->IsUniqueName());
828 Object* key = trap_result->get(i);
829 int* entry = unchecked_result_keys.Get(key);
830 if (*entry != kPresent) {
831 *entry = kPresent;
832 unchecked_result_keys_size++;
833 }
834 }
835 // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
836 for (int i = 0; i < nonconfigurable_keys_length; ++i) {
837 Object* key = target_nonconfigurable_keys->get(i);
838 // 17a. If key is not an element of uncheckedResultKeys, throw a
839 // TypeError exception.
840 int* found = unchecked_result_keys.Find(key);
841 if (found == nullptr || *found == kGone) {
842 isolate_->Throw(*isolate_->factory()->NewTypeError(
843 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_)));
844 return Nothing<bool>();
845 }
846 // 17b. Remove key from uncheckedResultKeys.
847 *found = kGone;
848 unchecked_result_keys_size--;
849 }
850 // 18. If extensibleTarget is true, return trapResult.
851 if (extensible_target) {
852 return this->AddKeysFromProxy(proxy, trap_result);
853 }
854 // 19. Repeat, for each key that is an element of targetConfigurableKeys:
855 for (int i = 0; i < target_configurable_keys->length(); ++i) {
856 Object* key = target_configurable_keys->get(i);
857 if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
858 // 19a. If key is not an element of uncheckedResultKeys, throw a
859 // TypeError exception.
860 int* found = unchecked_result_keys.Find(key);
861 if (found == nullptr || *found == kGone) {
862 isolate_->Throw(*isolate_->factory()->NewTypeError(
863 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_)));
864 return Nothing<bool>();
865 }
866 // 19b. Remove key from uncheckedResultKeys.
867 *found = kGone;
868 unchecked_result_keys_size--;
869 }
870 // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
871 if (unchecked_result_keys_size != 0) {
872 DCHECK_GT(unchecked_result_keys_size, 0);
873 isolate_->Throw(*isolate_->factory()->NewTypeError(
874 MessageTemplate::kProxyOwnKeysNonExtensible));
875 return Nothing<bool>();
876 }
877 // 21. Return trapResult.
878 return this->AddKeysFromProxy(proxy, trap_result);
879 }
880
464 } // namespace internal 881 } // namespace internal
465 } // namespace v8 882 } // namespace v8
OLDNEW
« no previous file with comments | « src/keys.h ('k') | src/messages.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698