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