1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Copyright 2013 the V8 project authors. All rights reserved. 2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// found in the LICENSE file. 4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 53b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch#include "src/keys.h" 6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 7bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/api-arguments.h" 8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/elements.h" 9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/factory.h" 10bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/identity-map.h" 11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/isolate-inl.h" 12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/objects-inl.h" 13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/property-descriptor.h" 143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch#include "src/prototype.h" 15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace v8 { 17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace internal { 18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochKeyAccumulator::~KeyAccumulator() { 20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 22bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochnamespace { 23bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 24bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochstatic bool ContainsOnlyValidKeys(Handle<FixedArray> array) { 25bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int len = array->length(); 26bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch for (int i = 0; i < len; i++) { 27bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Object* e = array->get(i); 28bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (!(e->IsName() || e->IsNumber())) return false; 29bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 30bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return true; 31bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 32bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 33bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} // namespace 34f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 35f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// static 36bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochMaybeHandle<FixedArray> KeyAccumulator::GetKeys( 3713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter, 38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch GetKeysConversion keys_conversion, bool is_for_in) { 39bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Isolate* isolate = object->GetIsolate(); 40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch FastKeyAccumulator accumulator(isolate, object, mode, filter); 4113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch accumulator.set_is_for_in(is_for_in); 4213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return accumulator.GetKeys(keys_conversion); 43bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 44bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 45014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochHandle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { 4613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (keys_.is_null()) { 47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return isolate_->factory()->empty_fixed_array(); 48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 4913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (mode_ == KeyCollectionMode::kOwnOnly && 5013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch keys_->map() == isolate_->heap()->fixed_array_map()) { 5113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return Handle<FixedArray>::cast(keys_); 52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 5313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch USE(ContainsOnlyValidKeys); 5413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<FixedArray> result = 5513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch OrderedHashSet::ConvertToKeysArray(keys(), convert); 5613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK(ContainsOnlyValidKeys(result)); 57014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return result; 58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 6013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochvoid KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { 6113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch AddKey(handle(key, isolate_), convert); 62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 6413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochvoid KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { 65014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (key->IsSymbol()) { 6613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (filter_ & SKIP_SYMBOLS) return; 6713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (Handle<Symbol>::cast(key)->is_private()) return; 6813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } else if (filter_ & SKIP_STRINGS) { 6913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return; 70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (IsShadowed(key)) return; 7213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (keys_.is_null()) { 7313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch keys_ = OrderedHashSet::Allocate(isolate_, 16); 74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 7513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch uint32_t index; 7613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() && 7713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<String>::cast(key)->AsArrayIndex(&index)) { 7813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch key = isolate_->factory()->NewNumberFromUint(index); 79014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 8013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch keys_ = OrderedHashSet::Add(keys(), key); 81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid KeyAccumulator::AddKeys(Handle<FixedArray> array, 84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch AddKeyConversion convert) { 85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int add_length = array->length(); 86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < add_length; i++) { 87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Handle<Object> current(array->get(i), isolate_); 88014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch AddKey(current, convert); 89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid KeyAccumulator::AddKeys(Handle<JSObject> array_like, 93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch AddKeyConversion convert) { 94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); 95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ElementsAccessor* accessor = array_like->GetElementsAccessor(); 96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch accessor->AddElementsToKeyAccumulator(array_like, this, convert); 97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 99f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochMaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator, 100f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<JSProxy> owner, 101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Handle<FixedArray> keys, 102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch PropertyFilter filter) { 103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (filter == ALL_PROPERTIES) { 104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Nothing to do. 105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return keys; 106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 107f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Isolate* isolate = accumulator->isolate(); 108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int store_position = 0; 109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < keys->length(); ++i) { 110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Handle<Name> key(Name::cast(keys->get(i)), isolate); 111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (key->FilterKey(filter)) continue; // Skip this key. 112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (filter & ONLY_ENUMERABLE) { 113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch PropertyDescriptor desc; 114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Maybe<bool> found = 115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc); 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch MAYBE_RETURN(found, MaybeHandle<FixedArray>()); 117f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (!found.FromJust()) continue; 118f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (!desc.enumerable()) { 119f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch accumulator->AddShadowingKey(key); 120f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue; 121f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Keep this key. 124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (store_position != i) { 125014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch keys->set(store_position, *key); 126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch store_position++; 128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (store_position == 0) return isolate->factory()->empty_fixed_array(); 130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch keys->Shrink(store_position); 131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return keys; 132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 133014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Returns "nothing" in case of exception, "true" on success. 135bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochMaybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy, 136bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> keys) { 137f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Postpone the enumerable check for for-in to the ForInFilter step. 138f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (!is_for_in_) { 1393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch ASSIGN_RETURN_ON_EXCEPTION_VALUE( 140f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch isolate_, keys, FilterProxyKeys(this, proxy, keys, filter_), 1413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Nothing<bool>()); 142f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (mode_ == KeyCollectionMode::kOwnOnly) { 143f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // If we collect only the keys from a JSProxy do not sort or deduplicate. 144f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch keys_ = keys; 145f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return Just(true); 146f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 147109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 14813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT); 149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return Just(true); 150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} 151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 152bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochMaybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, 153bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSReceiver> object) { 154bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // Proxies have no hidden prototype and we should not trigger the 155bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // [[GetPrototypeOf]] trap on the last iteration when using 156bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // AdvanceFollowingProxies. 15713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) { 158bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)), 159bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Nothing<bool>()); 160bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Just(true); 161bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 162bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 16313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly 164bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ? PrototypeIterator::END_AT_NON_HIDDEN 165bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch : PrototypeIterator::END_AT_NULL; 16613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end); 167bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch !iter.IsAtEnd();) { 168f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Start the shadow checks only after the first prototype has added 169f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // shadowing keys. 170f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (HasShadowingKeys()) skip_shadow_check_ = false; 171bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSReceiver> current = 172bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch PrototypeIterator::GetCurrent<JSReceiver>(iter); 173bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Maybe<bool> result = Just(false); // Dummy initialization. 174bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (current->IsJSProxy()) { 175bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); 176bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else { 177bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DCHECK(current->IsJSObject()); 178bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); 179bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 180bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MAYBE_RETURN(result, Nothing<bool>()); 181bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (!result.FromJust()) break; // |false| means "stop iterating". 182bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // Iterate through proxies but ignore access checks for the ALL_CAN_READ 183bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // case on API objects for OWN_ONLY keys handled in CollectOwnKeys. 184bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { 185bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Nothing<bool>(); 186bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 18713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!last_non_empty_prototype_.is_null() && 18813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch *last_non_empty_prototype_ == *current) { 18913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch break; 19013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 191bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 192bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Just(true); 193bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 194bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 195f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochbool KeyAccumulator::HasShadowingKeys() { return !shadowing_keys_.is_null(); } 196f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 197f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochbool KeyAccumulator::IsShadowed(Handle<Object> key) { 198f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (!HasShadowingKeys() || skip_shadow_check_) return false; 199f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return shadowing_keys_->Has(isolate_, key); 200f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch} 201f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 202f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid KeyAccumulator::AddShadowingKey(Object* key) { 203f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (mode_ == KeyCollectionMode::kOwnOnly) return; 204f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch AddShadowingKey(handle(key, isolate_)); 205f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch} 206f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid KeyAccumulator::AddShadowingKey(Handle<Object> key) { 207f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (mode_ == KeyCollectionMode::kOwnOnly) return; 208f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (shadowing_keys_.is_null()) { 209f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch shadowing_keys_ = ObjectHashSet::New(isolate_, 16); 210f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 211f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch shadowing_keys_ = ObjectHashSet::Add(shadowing_keys_, key); 212f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch} 213f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 2143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochnamespace { 2153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochvoid TrySettingEmptyEnumCache(JSReceiver* object) { 2173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Map* map = object->map(); 2183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength()); 2193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (!map->OnlyHasSimpleProperties()) return; 2203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (map->IsJSProxyMap()) return; 2213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (map->NumberOfOwnDescriptors() > 0) { 2223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch int number_of_enumerable_own_properties = 2233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS); 2243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (number_of_enumerable_own_properties > 0) return; 2253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch DCHECK(object->IsJSObject()); 2273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch map->SetEnumLength(0); 2283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 2293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 23062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochbool CheckAndInitalizeEmptyEnumCache(JSReceiver* object) { 2313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) { 2323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch TrySettingEmptyEnumCache(object); 2333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (object->map()->EnumLength() != 0) return false; 2353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch DCHECK(object->IsJSObject()); 2363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return !JSObject::cast(object)->HasEnumerableElements(); 2373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 2383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} // namespace 2393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochvoid FastKeyAccumulator::Prepare() { 2413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch DisallowHeapAllocation no_gc; 2423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Directly go for the fast path for OWN_ONLY keys. 24313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (mode_ == KeyCollectionMode::kOwnOnly) return; 2443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Fully walk the prototype chain and find the last prototype with keys. 2453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch is_receiver_simple_enum_ = false; 2463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch has_empty_prototype_ = true; 24713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch JSReceiver* last_prototype = nullptr; 2483b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd(); 2493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch iter.Advance()) { 2503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch JSReceiver* current = iter.GetCurrent<JSReceiver>(); 25162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current); 25213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (has_no_properties) continue; 25313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch last_prototype = current; 2543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch has_empty_prototype_ = false; 2553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 25613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (has_empty_prototype_) { 25713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch is_receiver_simple_enum_ = 25813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && 25913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch !JSObject::cast(*receiver_)->HasEnumerableElements(); 26013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } else if (last_prototype != nullptr) { 26113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch last_non_empty_prototype_ = handle(last_prototype, isolate_); 26213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 2633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 2643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochnamespace { 266bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochstatic Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate, 267bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> array, 268bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int length) { 269bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DCHECK_LE(length, array->length()); 270bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (array->length() == length) return array; 271bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return isolate->factory()->CopyFixedArrayUpTo(array, length); 272bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 273bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 27462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Initializes and directly returns the enume cache. Users of this function 27562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// have to make sure to never directly leak the enum cache. 276bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochHandle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, 277bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSObject> object) { 278bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<Map> map(object->map()); 279bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch bool cache_enum_length = map->OnlyHasSimpleProperties(); 280bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 281bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<DescriptorArray> descs = 282bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<DescriptorArray>(map->instance_descriptors(), isolate); 283bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int own_property_count = map->EnumLength(); 284bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // If the enum length of the given map is set to kInvalidEnumCache, this 285bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // means that the map itself has never used the present enum cache. The 286bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // first step to using the cache is to set the enum length of the map by 287bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // counting the number of own descriptors that are ENUMERABLE_STRINGS. 288bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (own_property_count == kInvalidEnumCacheSentinel) { 289bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch own_property_count = 290bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS); 291bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else { 292bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DCHECK( 293bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch own_property_count == 294bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS)); 295bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 296bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 297bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (descs->HasEnumCache()) { 298bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> keys(descs->GetEnumCache(), isolate); 299bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // In case the number of properties required in the enum are actually 300bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // present, we can reuse the enum cache. Otherwise, this means that the 301bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // enum cache was generated for a previous (smaller) version of the 302bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // Descriptor Array. In that case we regenerate the enum cache. 303bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (own_property_count <= keys->length()) { 304bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate->counters()->enum_cache_hits()->Increment(); 305bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (cache_enum_length) map->SetEnumLength(own_property_count); 306bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return ReduceFixedArrayTo(isolate, keys, own_property_count); 307bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 308bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 309bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 310bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (descs->IsEmpty()) { 311bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate->counters()->enum_cache_hits()->Increment(); 312bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (cache_enum_length) map->SetEnumLength(0); 313bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return isolate->factory()->empty_fixed_array(); 314bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 315bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 316bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate->counters()->enum_cache_misses()->Increment(); 317bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 318bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> storage = 319bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate->factory()->NewFixedArray(own_property_count); 320bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> indices = 321bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate->factory()->NewFixedArray(own_property_count); 322bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 323bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int size = map->NumberOfOwnDescriptors(); 324bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int index = 0; 325bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 326bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch for (int i = 0; i < size; i++) { 327bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch PropertyDetails details = descs->GetDetails(i); 328bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (details.IsDontEnum()) continue; 329bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Object* key = descs->GetKey(i); 330bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (key->IsSymbol()) continue; 331bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch storage->set(index, key); 332bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (!indices.is_null()) { 33362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch if (details.location() == kField) { 33462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch DCHECK_EQ(kData, details.kind()); 335bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); 336bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int load_by_field_index = field_index.GetLoadByFieldIndex(); 337bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch indices->set(index, Smi::FromInt(load_by_field_index)); 33862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch } else { 33962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch indices = Handle<FixedArray>(); 340bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 341bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 342bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch index++; 343bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 344bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DCHECK(index == storage->length()); 345bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 346bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DescriptorArray::SetEnumCache(descs, isolate, storage, indices); 347bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (cache_enum_length) { 348bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch map->SetEnumLength(own_property_count); 349bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 350bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return storage; 351bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 3523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochtemplate <bool fast_properties> 354f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochMaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, 355f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<JSObject> object, 356f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch GetKeysConversion convert) { 3573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Handle<FixedArray> keys; 3583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch ElementsAccessor* accessor = object->GetElementsAccessor(); 3593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (fast_properties) { 360bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch keys = GetFastEnumPropertyKeys(isolate, object); 3613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } else { 3623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // TODO(cbruni): preallocate big enough array to also hold elements. 363f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate, object); 3643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 365f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch MaybeHandle<FixedArray> result = 3663b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE); 3673b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (FLAG_trace_for_in_enumerate) { 3693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n", 370f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch keys->length(), result.ToHandleChecked()->length() - keys->length()); 3713b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 3723b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return result; 3733b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 3743b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3753b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochbool OnlyHasSimpleProperties(Map* map) { 3763b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER; 3773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 3783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3793b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} // namespace 3803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 38113e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybeHandle<FixedArray> FastKeyAccumulator::GetKeys( 38213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch GetKeysConversion keys_conversion) { 383f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (filter_ == ENUMERABLE_STRINGS) { 384f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<FixedArray> keys; 385f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (GetKeysFast(keys_conversion).ToHandle(&keys)) { 386f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return keys; 387f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 388f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (isolate_->has_pending_exception()) return MaybeHandle<FixedArray>(); 3893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 390f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 39113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return GetKeysSlow(keys_conversion); 3923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 3933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3943b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochMaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( 39513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch GetKeysConversion keys_conversion) { 39613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly; 3973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Map* map = receiver_->map(); 3983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (!own_only || !OnlyHasSimpleProperties(map)) { 3993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return MaybeHandle<FixedArray>(); 4003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 4013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // From this point on we are certiain to only collect own keys. 4033b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch DCHECK(receiver_->IsJSObject()); 4043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Handle<JSObject> object = Handle<JSObject>::cast(receiver_); 4053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Do not try to use the enum-cache for dict-mode objects. 4073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (map->is_dictionary_map()) { 40813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion); 4093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 4103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch int enum_length = receiver_->map()->EnumLength(); 4113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (enum_length == kInvalidEnumCacheSentinel) { 4123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Handle<FixedArray> keys; 4133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Try initializing the enum cache and return own properties. 41462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) { 4153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (FLAG_trace_for_in_enumerate) { 4163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n", 4173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch keys->length()); 4183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 4193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch is_receiver_simple_enum_ = 4203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch object->map()->EnumLength() != kInvalidEnumCacheSentinel; 4213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return keys; 4223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 4233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 4243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // The properties-only case failed because there were probably elements on the 4253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // receiver. 42613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion); 4273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 4283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 42962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochMaybeHandle<FixedArray> 43062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochFastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() { 43162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch Handle<JSObject> object = Handle<JSObject>::cast(receiver_); 43262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // Uninitalized enum cache 43362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch Map* map = object->map(); 43462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch if (object->elements()->length() != 0) { 43562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // Assume that there are elements. 43662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch return MaybeHandle<FixedArray>(); 43762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch } 43862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 43962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch if (number_of_own_descriptors == 0) { 44062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch map->SetEnumLength(0); 44162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch return isolate_->factory()->empty_fixed_array(); 44262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch } 44362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // We have no elements but possibly enumerable property keys, hence we can 44462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // directly initialize the enum cache. 44562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object); 44662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch if (is_for_in_) return keys; 44762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // Do not leak the enum cache as it might end up as an elements backing store. 44862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch return isolate_->factory()->CopyFixedArray(keys); 44962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch} 45062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch 4513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochMaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( 45213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch GetKeysConversion keys_conversion) { 45313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch KeyAccumulator accumulator(isolate_, mode_, filter_); 45413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch accumulator.set_is_for_in(is_for_in_); 45513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch accumulator.set_last_non_empty_prototype(last_non_empty_prototype_); 45613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 45713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_), 45813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MaybeHandle<FixedArray>()); 45913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return accumulator.GetKeys(keys_conversion); 4603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 46213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochnamespace { 46313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 464bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochenum IndexedOrNamed { kIndexed, kNamed }; 465bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 466bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// Returns |true| on success, |nothing| on exception. 467bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochtemplate <class Callback, IndexedOrNamed type> 46813e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver, 46913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<JSObject> object, 47013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<InterceptorInfo> interceptor, 47113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch KeyAccumulator* accumulator) { 472bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Isolate* isolate = accumulator->isolate(); 473bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 474bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch *object, Object::DONT_THROW); 475bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSObject> result; 47613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!interceptor->enumerator()->IsUndefined(isolate)) { 477bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator()); 478bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch const char* log_tag = type == kIndexed ? "interceptor-indexed-enum" 479bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch : "interceptor-named-enum"; 480bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch LOG(isolate, ApiObjectAccess(log_tag, *object)); 481bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch result = args.Call(enum_fun); 482bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 483bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 484bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (result.is_null()) return Just(true); 48513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch accumulator->AddKeys( 48613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT); 48713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return Just(true); 48813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch} 48913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 49013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <class Callback, IndexedOrNamed type> 49113e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver, 49213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<JSObject> object, 49313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch KeyAccumulator* accumulator) { 49413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Isolate* isolate = accumulator->isolate(); 495bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (type == kIndexed) { 49613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!object->HasIndexedInterceptor()) return Just(true); 497bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else { 49813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!object->HasNamedInterceptor()) return Just(true); 499bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 50013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<InterceptorInfo> interceptor(type == kIndexed 50113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch ? object->GetIndexedInterceptor() 50213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch : object->GetNamedInterceptor(), 50313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch isolate); 50413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if ((accumulator->filter() & ONLY_ALL_CAN_READ) && 50513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch !interceptor->all_can_read()) { 50613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return Just(true); 50713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 50813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return CollectInterceptorKeysInternal<Callback, type>( 50913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch receiver, object, interceptor, accumulator); 510bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 511bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 51213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch} // namespace 51313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 51413e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybe<bool> KeyAccumulator::CollectOwnElementIndices( 51513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<JSReceiver> receiver, Handle<JSObject> object) { 51613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true); 51713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 518bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ElementsAccessor* accessor = object->GetElementsAccessor(); 519bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch accessor->CollectElementIndices(object, this); 52013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 52113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return CollectInterceptorKeys<v8::IndexedPropertyEnumeratorCallback, 52213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch kIndexed>(receiver, object, this); 523bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 524bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 52513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochnamespace { 52613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 52713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <bool skip_symbols> 52813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochint CollectOwnPropertyNamesInternal(Handle<JSObject> object, 52913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch KeyAccumulator* keys, 53013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<DescriptorArray> descs, 53113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch int start_index, int limit) { 53213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch int first_skipped = -1; 533f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch PropertyFilter filter = keys->filter(); 534f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch KeyCollectionMode mode = keys->mode(); 53513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch for (int i = start_index; i < limit; i++) { 536f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch bool is_shadowing_key = false; 53713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch PropertyDetails details = descs->GetDetails(i); 538f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 539f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if ((details.attributes() & filter) != 0) { 540f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (mode == KeyCollectionMode::kIncludePrototypes) { 541f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch is_shadowing_key = true; 542f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else { 543f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue; 544f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 545f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 546f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 547f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (filter & ONLY_ALL_CAN_READ) { 54813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (details.kind() != kAccessor) continue; 54913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* accessors = descs->GetValue(i); 55013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!accessors->IsAccessorInfo()) continue; 55113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!AccessorInfo::cast(accessors)->all_can_read()) continue; 552bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 553f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 55413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Name* key = descs->GetKey(i); 55513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (skip_symbols == key->IsSymbol()) { 55613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (first_skipped == -1) first_skipped = i; 55713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch continue; 55813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 55913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (key->FilterKey(keys->filter())) continue; 560f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 561f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (is_shadowing_key) { 562f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch keys->AddShadowingKey(key); 563f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else { 564f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch keys->AddKey(key, DO_NOT_CONVERT); 565f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 56613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 56713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return first_skipped; 56813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch} 56913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 570f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochtemplate <class T> 571f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochHandle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate, 572f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch KeyCollectionMode mode, 573f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch KeyAccumulator* accumulator, 574f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<JSObject> object, 575f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch T* raw_dictionary) { 576f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<T> dictionary(raw_dictionary, isolate); 577f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch int length = dictionary->NumberOfEnumElements(); 578f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (length == 0) { 579f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return isolate->factory()->empty_fixed_array(); 580f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 581f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); 582f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch T::CopyEnumKeysTo(dictionary, storage, mode, accumulator); 583f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return storage; 584f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch} 58513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch} // namespace 58613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 58713e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver, 58813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<JSObject> object) { 58913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (filter_ == ENUMERABLE_STRINGS) { 590f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<FixedArray> enum_keys; 591f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (object->HasFastProperties()) { 592f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, object); 593f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // If the number of properties equals the length of enumerable properties 594f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // we do not have to filter out non-enumerable ones 595f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Map* map = object->map(); 596f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch int nof_descriptors = map->NumberOfOwnDescriptors(); 597f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (enum_keys->length() != nof_descriptors) { 598f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<DescriptorArray> descs = 599f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Handle<DescriptorArray>(map->instance_descriptors(), isolate_); 600f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for (int i = 0; i < nof_descriptors; i++) { 601f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch PropertyDetails details = descs->GetDetails(i); 602f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (!details.IsDontEnum()) continue; 603f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Object* key = descs->GetKey(i); 604f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch this->AddShadowingKey(key); 605f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 606f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 607f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else if (object->IsJSGlobalObject()) { 608f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch enum_keys = GetOwnEnumPropertyDictionaryKeys( 609f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch isolate_, mode_, this, object, object->global_dictionary()); 610f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else { 611f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch enum_keys = GetOwnEnumPropertyDictionaryKeys( 612f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch isolate_, mode_, this, object, object->property_dictionary()); 613f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 61413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch AddKeys(enum_keys, DO_NOT_CONVERT); 615bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else { 61613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (object->HasFastProperties()) { 61713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch int limit = object->map()->NumberOfOwnDescriptors(); 61813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<DescriptorArray> descs(object->map()->instance_descriptors(), 61913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch isolate_); 62013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // First collect the strings, 62113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch int first_symbol = 62213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit); 62313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // then the symbols. 62413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (first_symbol != -1) { 62513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch CollectOwnPropertyNamesInternal<false>(object, this, descs, 62613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch first_symbol, limit); 62713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 62813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } else if (object->IsJSGlobalObject()) { 62913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch GlobalDictionary::CollectKeysTo( 630f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch handle(object->global_dictionary(), isolate_), this); 63113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } else { 63213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch NameDictionary::CollectKeysTo( 633f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch handle(object->property_dictionary(), isolate_), this); 63413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 635bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 63613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Add the property keys from the interceptor. 63713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return CollectInterceptorKeys<v8::GenericNamedPropertyEnumeratorCallback, 63813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch kNamed>(receiver, object, this); 63913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch} 64013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 64113e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys( 64213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver, 64313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<JSObject> object) { 64413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MAYBE_RETURN( 64513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch (CollectInterceptorKeysInternal<v8::IndexedPropertyEnumeratorCallback, 64613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch kIndexed>( 64713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch receiver, object, 64813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch handle( 64913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch InterceptorInfo::cast(access_check_info->indexed_interceptor()), 65013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch isolate_), 65113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch this)), 65213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Nothing<bool>()); 65313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MAYBE_RETURN( 65413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch (CollectInterceptorKeysInternal< 65513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch v8::GenericNamedPropertyEnumeratorCallback, kNamed>( 65613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch receiver, object, 65713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch handle(InterceptorInfo::cast(access_check_info->named_interceptor()), 65813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch isolate_), 65913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch this)), 66013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Nothing<bool>()); 66113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return Just(true); 662bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 663bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 664bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// Returns |true| on success, |false| if prototype walking should be stopped, 665bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// |nothing| if an exception was thrown. 666bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochMaybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, 667bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSObject> object) { 668bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // Check access rights if required. 669bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (object->IsAccessCheckNeeded() && 670bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch !isolate_->MayAccess(handle(isolate_->context()), object)) { 671bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // The cross-origin spec says that [[Enumerate]] shall return an empty 672bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // iterator when it doesn't have access... 67313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (mode_ == KeyCollectionMode::kIncludePrototypes) { 674bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Just(false); 675bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 676bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. 67713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK(KeyCollectionMode::kOwnOnly == mode_); 67813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Handle<AccessCheckInfo> access_check_info; 67913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch { 68013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DisallowHeapAllocation no_gc; 68113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch AccessCheckInfo* maybe_info = AccessCheckInfo::Get(isolate_, object); 68213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (maybe_info) access_check_info = handle(maybe_info, isolate_); 68313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 68413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // We always have both kinds of interceptors or none. 68513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (!access_check_info.is_null() && 68613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch access_check_info->named_interceptor()) { 68713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MAYBE_RETURN(CollectAccessCheckInterceptorKeys(access_check_info, 68813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch receiver, object), 68913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Nothing<bool>()); 69013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return Just(false); 69113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 692bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); 693bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 69413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>()); 69513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>()); 696bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Just(true); 697bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 698bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 699bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// static 700f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochHandle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys( 701bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Isolate* isolate, Handle<JSObject> object) { 702bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (object->HasFastProperties()) { 703bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return GetFastEnumPropertyKeys(isolate, object); 704bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else if (object->IsJSGlobalObject()) { 705f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return GetOwnEnumPropertyDictionaryKeys( 706f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch isolate, KeyCollectionMode::kOwnOnly, nullptr, object, 707f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch object->global_dictionary()); 708bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else { 709f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return GetOwnEnumPropertyDictionaryKeys( 710f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch isolate, KeyCollectionMode::kOwnOnly, nullptr, object, 711f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch object->property_dictionary()); 712bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 713bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 714bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 715bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// ES6 9.5.12 716bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// Returns |true| on success, |nothing| in case of exception. 717bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochMaybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver, 718bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSProxy> proxy) { 719bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch STACK_CHECK(isolate_, Nothing<bool>()); 720bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. 721bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<Object> handler(proxy->handler(), isolate_); 722bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 2. If handler is null, throw a TypeError exception. 723bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 3. Assert: Type(handler) is Object. 724bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (proxy->IsRevoked()) { 725bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_->Throw(*isolate_->factory()->NewTypeError( 726bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string())); 727bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Nothing<bool>(); 728bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 729bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. 730bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSReceiver> target(proxy->target(), isolate_); 731bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 5. Let trap be ? GetMethod(handler, "ownKeys"). 732bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<Object> trap; 733bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ASSIGN_RETURN_ON_EXCEPTION_VALUE( 734bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), 735bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_->factory()->ownKeys_string()), 736bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Nothing<bool>()); 737bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 6. If trap is undefined, then 73813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (trap->IsUndefined(isolate_)) { 739bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 6a. Return target.[[OwnPropertyKeys]](). 740bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return CollectOwnJSProxyTargetKeys(proxy, target); 741bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 742bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 7. Let trapResultArray be Call(trap, handler, «target»). 743bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<Object> trap_result_array; 744bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<Object> args[] = {target}; 745bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ASSIGN_RETURN_ON_EXCEPTION_VALUE( 746bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_, trap_result_array, 747bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Execution::Call(isolate_, trap, handler, arraysize(args), args), 748bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Nothing<bool>()); 749bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, 750bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // «String, Symbol»). 751bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> trap_result; 752bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ASSIGN_RETURN_ON_EXCEPTION_VALUE( 753bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_, trap_result, 754bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Object::CreateListFromArrayLike(isolate_, trap_result_array, 755bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ElementTypes::kStringAndSymbol), 756bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Nothing<bool>()); 757bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 9. Let extensibleTarget be ? IsExtensible(target). 758bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); 759bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MAYBE_RETURN(maybe_extensible, Nothing<bool>()); 760bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch bool extensible_target = maybe_extensible.FromJust(); 761bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 10. Let targetKeys be ? target.[[OwnPropertyKeys]](). 762bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> target_keys; 763bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys, 764bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch JSReceiver::OwnPropertyKeys(target), 765bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Nothing<bool>()); 766bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 11. (Assert) 767bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 12. Let targetConfigurableKeys be an empty List. 768bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // To save memory, we're re-using target_keys and will modify it in-place. 769bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> target_configurable_keys = target_keys; 770bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 13. Let targetNonconfigurableKeys be an empty List. 771bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> target_nonconfigurable_keys = 772bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_->factory()->NewFixedArray(target_keys->length()); 773bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int nonconfigurable_keys_length = 0; 774bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 14. Repeat, for each element key of targetKeys: 775bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch for (int i = 0; i < target_keys->length(); ++i) { 776bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 14a. Let desc be ? target.[[GetOwnProperty]](key). 777bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch PropertyDescriptor desc; 778bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor( 779bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_, target, handle(target_keys->get(i), isolate_), &desc); 780bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MAYBE_RETURN(found, Nothing<bool>()); 781bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 14b. If desc is not undefined and desc.[[Configurable]] is false, then 782bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (found.FromJust() && !desc.configurable()) { 783bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 14b i. Append key as an element of targetNonconfigurableKeys. 784bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch target_nonconfigurable_keys->set(nonconfigurable_keys_length, 785bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch target_keys->get(i)); 786bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch nonconfigurable_keys_length++; 787bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // The key was moved, null it out in the original list. 788c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch target_keys->set(i, Smi::kZero); 789bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } else { 790bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 14c. Else, 791bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 14c i. Append key as an element of targetConfigurableKeys. 792bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // (No-op, just keep it in |target_keys|.) 793bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 794bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 795bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty, 796bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // then: 797bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (extensible_target && nonconfigurable_keys_length == 0) { 798bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 15a. Return trapResult. 799bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return AddKeysFromJSProxy(proxy, trap_result); 800bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 801bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult. 802c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch Zone set_zone(isolate_->allocator(), ZONE_NAME); 803bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch const int kPresent = 1; 804bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch const int kGone = 0; 80562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch IdentityMap<int, ZoneAllocationPolicy> unchecked_result_keys( 80662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch isolate_->heap(), ZoneAllocationPolicy(&set_zone)); 807bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int unchecked_result_keys_size = 0; 808bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch for (int i = 0; i < trap_result->length(); ++i) { 809bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DCHECK(trap_result->get(i)->IsUniqueName()); 810bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Object* key = trap_result->get(i); 811bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int* entry = unchecked_result_keys.Get(key); 812bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (*entry != kPresent) { 813bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch *entry = kPresent; 814bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch unchecked_result_keys_size++; 815bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 816bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 817bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 17. Repeat, for each key that is an element of targetNonconfigurableKeys: 818bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch for (int i = 0; i < nonconfigurable_keys_length; ++i) { 819bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Object* key = target_nonconfigurable_keys->get(i); 820bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 17a. If key is not an element of uncheckedResultKeys, throw a 821bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // TypeError exception. 822bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int* found = unchecked_result_keys.Find(key); 823bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (found == nullptr || *found == kGone) { 824bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_->Throw(*isolate_->factory()->NewTypeError( 825bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_))); 826bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Nothing<bool>(); 827bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 828bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 17b. Remove key from uncheckedResultKeys. 829bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch *found = kGone; 830bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch unchecked_result_keys_size--; 831bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 832bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 18. If extensibleTarget is true, return trapResult. 833bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (extensible_target) { 834bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return AddKeysFromJSProxy(proxy, trap_result); 835bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 836bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 19. Repeat, for each key that is an element of targetConfigurableKeys: 837bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch for (int i = 0; i < target_configurable_keys->length(); ++i) { 838bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Object* key = target_configurable_keys->get(i); 839bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable. 840bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 19a. If key is not an element of uncheckedResultKeys, throw a 841bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // TypeError exception. 842bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch int* found = unchecked_result_keys.Find(key); 843bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (found == nullptr || *found == kGone) { 844bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_->Throw(*isolate_->factory()->NewTypeError( 845bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_))); 846bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Nothing<bool>(); 847bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 848bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 19b. Remove key from uncheckedResultKeys. 849bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch *found = kGone; 850bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch unchecked_result_keys_size--; 851bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 852bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 20. If uncheckedResultKeys is not empty, throw a TypeError exception. 853bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch if (unchecked_result_keys_size != 0) { 854bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch DCHECK_GT(unchecked_result_keys_size, 0); 855bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch isolate_->Throw(*isolate_->factory()->NewTypeError( 856bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch MessageTemplate::kProxyOwnKeysNonExtensible)); 857bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return Nothing<bool>(); 858bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch } 859bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // 21. Return trapResult. 860bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return AddKeysFromJSProxy(proxy, trap_result); 861bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 862bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 863bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben MurdochMaybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys( 864bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<JSProxy> proxy, Handle<JSReceiver> target) { 865bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch // TODO(cbruni): avoid creating another KeyAccumulator 866bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Handle<FixedArray> keys; 867bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch ASSIGN_RETURN_ON_EXCEPTION_VALUE( 86813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch isolate_, keys, 86913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch KeyAccumulator::GetKeys(target, KeyCollectionMode::kOwnOnly, filter_, 870f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch GetKeysConversion::kConvertToString, is_for_in_), 87113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Nothing<bool>()); 872bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); 873bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch return result; 874bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch} 875bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 876014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 877014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 878