| 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/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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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 | 
| OLD | NEW | 
|---|