V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
runtime-forin.cc
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/runtime/runtime-utils.h"
6 
7 #include "src/arguments-inl.h"
8 #include "src/counters.h"
9 #include "src/elements.h"
10 #include "src/heap/factory.h"
11 #include "src/isolate-inl.h"
12 #include "src/keys.h"
13 #include "src/objects-inl.h"
14 #include "src/objects/module.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 namespace {
20 
21 // Returns either a FixedArray or, if the given {receiver} has an enum cache
22 // that contains all enumerable properties of the {receiver} and its prototypes
23 // have none, the map of the {receiver}. This is used to speed up the check for
24 // deletions during a for-in.
25 MaybeHandle<HeapObject> Enumerate(Isolate* isolate,
26  Handle<JSReceiver> receiver) {
27  JSObject::MakePrototypesFast(receiver, kStartAtReceiver, isolate);
28  FastKeyAccumulator accumulator(isolate, receiver,
29  KeyCollectionMode::kIncludePrototypes,
30  ENUMERABLE_STRINGS, true);
31  // Test if we have an enum cache for {receiver}.
32  if (!accumulator.is_receiver_simple_enum()) {
33  Handle<FixedArray> keys;
34  ASSIGN_RETURN_ON_EXCEPTION(
35  isolate, keys, accumulator.GetKeys(GetKeysConversion::kConvertToString),
36  HeapObject);
37  // Test again, since cache may have been built by GetKeys() calls above.
38  if (!accumulator.is_receiver_simple_enum()) return keys;
39  }
40  DCHECK(!receiver->IsJSModuleNamespace());
41  return handle(receiver->map(), isolate);
42 }
43 
44 // This is a slight modifcation of JSReceiver::HasProperty, dealing with
45 // the oddities of JSProxy and JSModuleNamespace in for-in filter.
46 MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
47  Handle<JSReceiver> receiver,
48  Handle<Object> key) {
49  bool success = false;
50  Maybe<PropertyAttributes> result = Just(ABSENT);
51  LookupIterator it =
52  LookupIterator::PropertyOrElement(isolate, receiver, key, &success);
53  if (!success) return isolate->factory()->undefined_value();
54  for (; it.IsFound(); it.Next()) {
55  switch (it.state()) {
56  case LookupIterator::NOT_FOUND:
57  case LookupIterator::TRANSITION:
58  UNREACHABLE();
59  case LookupIterator::JSPROXY: {
60  // For proxies we have to invoke the [[GetOwnProperty]] trap.
61  result = JSProxy::GetPropertyAttributes(&it);
62  if (result.IsNothing()) return MaybeHandle<Object>();
63  if (result.FromJust() == ABSENT) {
64  // Continue lookup on the proxy's prototype.
65  Handle<JSProxy> proxy = it.GetHolder<JSProxy>();
66  Handle<Object> prototype;
67  ASSIGN_RETURN_ON_EXCEPTION(isolate, prototype,
68  JSProxy::GetPrototype(proxy), Object);
69  if (prototype->IsNull(isolate)) {
70  return isolate->factory()->undefined_value();
71  }
72  // We already have a stack-check in JSProxy::GetPrototype.
73  return HasEnumerableProperty(
74  isolate, Handle<JSReceiver>::cast(prototype), key);
75  } else if (result.FromJust() & DONT_ENUM) {
76  return isolate->factory()->undefined_value();
77  } else {
78  return it.GetName();
79  }
80  }
81  case LookupIterator::INTERCEPTOR: {
82  result = JSObject::GetPropertyAttributesWithInterceptor(&it);
83  if (result.IsNothing()) return MaybeHandle<Object>();
84  if (result.FromJust() != ABSENT) return it.GetName();
85  continue;
86  }
87  case LookupIterator::ACCESS_CHECK: {
88  if (it.HasAccess()) continue;
89  result = JSObject::GetPropertyAttributesWithFailedAccessCheck(&it);
90  if (result.IsNothing()) return MaybeHandle<Object>();
91  if (result.FromJust() != ABSENT) return it.GetName();
92  return isolate->factory()->undefined_value();
93  }
94  case LookupIterator::INTEGER_INDEXED_EXOTIC:
95  // TypedArray out-of-bounds access.
96  return isolate->factory()->undefined_value();
97  case LookupIterator::ACCESSOR: {
98  if (it.GetHolder<Object>()->IsJSModuleNamespace()) {
99  result = JSModuleNamespace::GetPropertyAttributes(&it);
100  if (result.IsNothing()) return MaybeHandle<Object>();
101  DCHECK_EQ(0, result.FromJust() & DONT_ENUM);
102  }
103  return it.GetName();
104  }
105  case LookupIterator::DATA:
106  return it.GetName();
107  }
108  }
109  return isolate->factory()->undefined_value();
110 }
111 
112 } // namespace
113 
114 
115 RUNTIME_FUNCTION(Runtime_ForInEnumerate) {
116  HandleScope scope(isolate);
117  DCHECK_EQ(1, args.length());
118  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
119  RETURN_RESULT_OR_FAILURE(isolate, Enumerate(isolate, receiver));
120 }
121 
122 
123 RUNTIME_FUNCTION(Runtime_ForInHasProperty) {
124  HandleScope scope(isolate);
125  DCHECK_EQ(2, args.length());
126  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
127  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
128  Handle<Object> result;
129  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
130  isolate, result, HasEnumerableProperty(isolate, receiver, key));
131  return isolate->heap()->ToBoolean(!result->IsUndefined(isolate));
132 }
133 
134 } // namespace internal
135 } // namespace v8
Definition: libplatform.h:13