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

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

Powered by Google App Engine
This is Rietveld 408576698