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/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
12 : #include "src/isolate-inl.h"
13 : #include "src/keys.h"
14 : #include "src/objects-inl.h"
15 : #include "src/objects/module.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.
26 54443 : MaybeHandle<HeapObject> Enumerate(Isolate* isolate,
27 : Handle<JSReceiver> receiver) {
28 54443 : 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 54443 : if (!accumulator.is_receiver_simple_enum()) {
34 : Handle<FixedArray> keys;
35 103188 : ASSIGN_RETURN_ON_EXCEPTION(
36 : isolate, keys, accumulator.GetKeys(GetKeysConversion::kConvertToString),
37 : HeapObject);
38 : // Test again, since cache may have been built by GetKeys() calls above.
39 51468 : if (!accumulator.is_receiver_simple_enum()) return keys;
40 : }
41 : DCHECK(!receiver->IsJSModuleNamespace());
42 7755 : return handle(receiver->map(), isolate);
43 : }
44 :
45 : // This is a slight modifcation of JSReceiver::HasProperty, dealing with
46 : // the oddities of JSProxy and JSModuleNamespace in for-in filter.
47 246045 : MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
48 : Handle<JSReceiver> receiver,
49 : Handle<Object> key) {
50 246045 : bool success = false;
51 : Maybe<PropertyAttributes> result = Just(ABSENT);
52 : LookupIterator it =
53 246045 : LookupIterator::PropertyOrElement(isolate, receiver, key, &success);
54 246045 : if (!success) return isolate->factory()->undefined_value();
55 733853 : for (; it.IsFound(); it.Next()) {
56 489931 : switch (it.state()) {
57 : case LookupIterator::NOT_FOUND:
58 : case LookupIterator::TRANSITION:
59 0 : UNREACHABLE();
60 : case LookupIterator::JSPROXY: {
61 : // For proxies we have to invoke the [[GetOwnProperty]] trap.
62 1197 : result = JSProxy::GetPropertyAttributes(&it);
63 1197 : if (result.IsNothing()) return MaybeHandle<Object>();
64 1170 : if (result.FromJust() == ABSENT) {
65 : // Continue lookup on the proxy's prototype.
66 81 : Handle<JSProxy> proxy = it.GetHolder<JSProxy>();
67 : Handle<Object> prototype;
68 162 : ASSIGN_RETURN_ON_EXCEPTION(isolate, prototype,
69 : JSProxy::GetPrototype(proxy), Object);
70 81 : if (prototype->IsNull(isolate)) {
71 9 : return isolate->factory()->undefined_value();
72 : }
73 : // We already have a stack-check in JSProxy::GetPrototype.
74 : return HasEnumerableProperty(
75 72 : isolate, Handle<JSReceiver>::cast(prototype), key);
76 1089 : } else if (result.FromJust() & DONT_ENUM) {
77 189 : return isolate->factory()->undefined_value();
78 : } else {
79 900 : return it.GetName();
80 : }
81 : }
82 : case LookupIterator::INTERCEPTOR: {
83 240249 : result = JSObject::GetPropertyAttributesWithInterceptor(&it);
84 240249 : if (result.IsNothing()) return MaybeHandle<Object>();
85 240249 : if (result.FromJust() != ABSENT) return it.GetName();
86 : continue;
87 : }
88 : case LookupIterator::ACCESS_CHECK: {
89 3870 : if (it.HasAccess()) continue;
90 0 : result = JSObject::GetPropertyAttributesWithFailedAccessCheck(&it);
91 0 : if (result.IsNothing()) return MaybeHandle<Object>();
92 0 : if (result.FromJust() != ABSENT) return it.GetName();
93 0 : return isolate->factory()->undefined_value();
94 : }
95 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
96 : // TypedArray out-of-bounds access.
97 0 : return isolate->factory()->undefined_value();
98 : case LookupIterator::ACCESSOR: {
99 63 : if (it.GetHolder<Object>()->IsJSModuleNamespace()) {
100 45 : result = JSModuleNamespace::GetPropertyAttributes(&it);
101 45 : if (result.IsNothing()) return MaybeHandle<Object>();
102 : DCHECK_EQ(0, result.FromJust() & DONT_ENUM);
103 : }
104 63 : return it.GetName();
105 : }
106 : case LookupIterator::DATA:
107 244552 : return it.GetName();
108 : }
109 : }
110 18 : return isolate->factory()->undefined_value();
111 : }
112 :
113 : } // namespace
114 :
115 :
116 108886 : RUNTIME_FUNCTION(Runtime_ForInEnumerate) {
117 : HandleScope scope(isolate);
118 : DCHECK_EQ(1, args.length());
119 54443 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
120 108886 : RETURN_RESULT_OR_FAILURE(isolate, Enumerate(isolate, receiver));
121 : }
122 :
123 :
124 491946 : RUNTIME_FUNCTION(Runtime_ForInHasProperty) {
125 : HandleScope scope(isolate);
126 : DCHECK_EQ(2, args.length());
127 245973 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
128 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
129 : Handle<Object> result;
130 491946 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
131 : isolate, result, HasEnumerableProperty(isolate, receiver, key));
132 : return isolate->heap()->ToBoolean(!result->IsUndefined(isolate));
133 : }
134 :
135 : } // namespace internal
136 121996 : } // namespace v8
|