Line data Source code
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 54274 : MaybeHandle<HeapObject> Enumerate(Isolate* isolate,
26 : Handle<JSReceiver> receiver) {
27 54274 : 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 54274 : if (!accumulator.is_receiver_simple_enum()) {
33 : Handle<FixedArray> keys;
34 102868 : 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 51317 : if (!accumulator.is_receiver_simple_enum()) return keys;
39 : }
40 : DCHECK(!receiver->IsJSModuleNamespace());
41 7796 : 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 246018 : MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
47 : Handle<JSReceiver> receiver,
48 : Handle<Object> key) {
49 246018 : bool success = false;
50 : Maybe<PropertyAttributes> result = Just(ABSENT);
51 : LookupIterator it =
52 246018 : LookupIterator::PropertyOrElement(isolate, receiver, key, &success);
53 246018 : if (!success) return isolate->factory()->undefined_value();
54 243850 : for (; it.IsFound(); it.Next()) {
55 489850 : switch (it.state()) {
56 : case LookupIterator::NOT_FOUND:
57 : case LookupIterator::TRANSITION:
58 0 : UNREACHABLE();
59 : case LookupIterator::JSPROXY: {
60 : // For proxies we have to invoke the [[GetOwnProperty]] trap.
61 1224 : result = JSProxy::GetPropertyAttributes(&it);
62 1224 : if (result.IsNothing()) return MaybeHandle<Object>();
63 1197 : if (result.FromJust() == ABSENT) {
64 : // Continue lookup on the proxy's prototype.
65 81 : Handle<JSProxy> proxy = it.GetHolder<JSProxy>();
66 : Handle<Object> prototype;
67 162 : ASSIGN_RETURN_ON_EXCEPTION(isolate, prototype,
68 : JSProxy::GetPrototype(proxy), Object);
69 162 : if (prototype->IsNull(isolate)) {
70 9 : return isolate->factory()->undefined_value();
71 : }
72 : // We already have a stack-check in JSProxy::GetPrototype.
73 : return HasEnumerableProperty(
74 72 : isolate, Handle<JSReceiver>::cast(prototype), key);
75 1116 : } else if (result.FromJust() & DONT_ENUM) {
76 198 : return isolate->factory()->undefined_value();
77 : } else {
78 918 : return it.GetName();
79 : }
80 : }
81 : case LookupIterator::INTERCEPTOR: {
82 240249 : result = JSObject::GetPropertyAttributesWithInterceptor(&it);
83 240249 : if (result.IsNothing()) return MaybeHandle<Object>();
84 240249 : if (result.FromJust() != ABSENT) return it.GetName();
85 : continue;
86 : }
87 : case LookupIterator::ACCESS_CHECK: {
88 3816 : if (it.HasAccess()) continue;
89 0 : result = JSObject::GetPropertyAttributesWithFailedAccessCheck(&it);
90 0 : if (result.IsNothing()) return MaybeHandle<Object>();
91 0 : if (result.FromJust() != ABSENT) return it.GetName();
92 0 : return isolate->factory()->undefined_value();
93 : }
94 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
95 : // TypedArray out-of-bounds access.
96 0 : return isolate->factory()->undefined_value();
97 : case LookupIterator::ACCESSOR: {
98 126 : if (it.GetHolder<Object>()->IsJSModuleNamespace()) {
99 45 : result = JSModuleNamespace::GetPropertyAttributes(&it);
100 45 : if (result.IsNothing()) return MaybeHandle<Object>();
101 : DCHECK_EQ(0, result.FromJust() & DONT_ENUM);
102 : }
103 63 : return it.GetName();
104 : }
105 : case LookupIterator::DATA:
106 244498 : return it.GetName();
107 : }
108 : }
109 18 : return isolate->factory()->undefined_value();
110 : }
111 :
112 : } // namespace
113 :
114 :
115 54274 : RUNTIME_FUNCTION(Runtime_ForInEnumerate) {
116 54274 : HandleScope scope(isolate);
117 : DCHECK_EQ(1, args.length());
118 108548 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
119 162822 : RETURN_RESULT_OR_FAILURE(isolate, Enumerate(isolate, receiver));
120 : }
121 :
122 :
123 245946 : RUNTIME_FUNCTION(Runtime_ForInHasProperty) {
124 245946 : HandleScope scope(isolate);
125 : DCHECK_EQ(2, args.length());
126 491892 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
127 245946 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
128 : Handle<Object> result;
129 491892 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
130 : isolate, result, HasEnumerableProperty(isolate, receiver, key));
131 491838 : return isolate->heap()->ToBoolean(!result->IsUndefined(isolate));
132 : }
133 :
134 : } // namespace internal
135 183867 : } // namespace v8
|