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