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.h"
8 : #include "src/elements.h"
9 : #include "src/factory.h"
10 : #include "src/isolate-inl.h"
11 : #include "src/keys.h"
12 : #include "src/objects-inl.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 : namespace {
18 :
19 : // Returns either a FixedArray or, if the given {receiver} has an enum cache
20 : // that contains all enumerable properties of the {receiver} and its prototypes
21 : // have none, the map of the {receiver}. This is used to speed up the check for
22 : // deletions during a for-in.
23 88190 : MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) {
24 : Isolate* const isolate = receiver->GetIsolate();
25 88190 : JSObject::MakePrototypesFast(receiver, kStartAtReceiver, isolate);
26 : FastKeyAccumulator accumulator(isolate, receiver,
27 : KeyCollectionMode::kIncludePrototypes,
28 : ENUMERABLE_STRINGS);
29 : accumulator.set_is_for_in(true);
30 : // Test if we have an enum cache for {receiver}.
31 88190 : if (!accumulator.is_receiver_simple_enum()) {
32 : Handle<FixedArray> keys;
33 167348 : ASSIGN_RETURN_ON_EXCEPTION(
34 : isolate, keys, accumulator.GetKeys(GetKeysConversion::kConvertToString),
35 : HeapObject);
36 : // Test again, since cache may have been built by GetKeys() calls above.
37 83534 : if (!accumulator.is_receiver_simple_enum()) return keys;
38 : }
39 : return handle(receiver->map(), isolate);
40 : }
41 :
42 : // This is a slight modifcation of JSReceiver::HasProperty, dealing with
43 : // the oddities of JSProxy in for-in filter.
44 287773 : MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
45 : Handle<JSReceiver> receiver,
46 : Handle<Object> key) {
47 287773 : bool success = false;
48 : Maybe<PropertyAttributes> result = Just(ABSENT);
49 : LookupIterator it =
50 287773 : LookupIterator::PropertyOrElement(isolate, receiver, key, &success);
51 287773 : if (!success) return isolate->factory()->undefined_value();
52 285451 : for (; it.IsFound(); it.Next()) {
53 573196 : switch (it.state()) {
54 : case LookupIterator::NOT_FOUND:
55 : case LookupIterator::TRANSITION:
56 0 : UNREACHABLE();
57 : case LookupIterator::JSPROXY: {
58 : // For proxies we have to invoke the [[GetOwnProperty]] trap.
59 1166 : result = JSProxy::GetPropertyAttributes(&it);
60 1166 : if (result.IsNothing()) return MaybeHandle<Object>();
61 1121 : if (result.FromJust() == ABSENT) {
62 : // Continue lookup on the proxy's prototype.
63 127 : Handle<JSProxy> proxy = it.GetHolder<JSProxy>();
64 : Handle<Object> prototype;
65 254 : ASSIGN_RETURN_ON_EXCEPTION(isolate, prototype,
66 : JSProxy::GetPrototype(proxy), Object);
67 127 : if (prototype->IsNull(isolate)) {
68 : return isolate->factory()->undefined_value();
69 : }
70 : // We already have a stack-check in JSProxy::GetPrototype.
71 : return HasEnumerableProperty(
72 112 : isolate, Handle<JSReceiver>::cast(prototype), key);
73 994 : } else if (result.FromJust() & DONT_ENUM) {
74 : return isolate->factory()->undefined_value();
75 : } else {
76 910 : return it.GetName();
77 : }
78 : }
79 : case LookupIterator::INTERCEPTOR: {
80 280284 : result = JSObject::GetPropertyAttributesWithInterceptor(&it);
81 280284 : if (result.IsNothing()) return MaybeHandle<Object>();
82 280284 : if (result.FromJust() != ABSENT) return it.GetName();
83 : continue;
84 : }
85 : case LookupIterator::ACCESS_CHECK: {
86 5411 : if (it.HasAccess()) continue;
87 0 : result = JSObject::GetPropertyAttributesWithFailedAccessCheck(&it);
88 0 : if (result.IsNothing()) return MaybeHandle<Object>();
89 0 : if (result.FromJust() != ABSENT) return it.GetName();
90 : return isolate->factory()->undefined_value();
91 : }
92 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
93 : // TypedArray out-of-bounds access.
94 : return isolate->factory()->undefined_value();
95 : case LookupIterator::ACCESSOR:
96 : case LookupIterator::DATA:
97 286335 : return it.GetName();
98 : }
99 : }
100 : return isolate->factory()->undefined_value();
101 : }
102 :
103 : } // namespace
104 :
105 :
106 71706 : RUNTIME_FUNCTION(Runtime_ForInEnumerate) {
107 35853 : HandleScope scope(isolate);
108 : DCHECK_EQ(1, args.length());
109 71706 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
110 107559 : RETURN_RESULT_OR_FAILURE(isolate, Enumerate(receiver));
111 : }
112 :
113 :
114 52337 : RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) {
115 52337 : HandleScope scope(isolate);
116 : DCHECK_EQ(1, args.length());
117 52337 : Handle<JSReceiver> receiver = args.at<JSReceiver>(0);
118 : Handle<Object> cache_type;
119 104674 : if (!Enumerate(receiver).ToHandle(&cache_type)) {
120 98 : return MakeTriple(isolate->heap()->exception(), nullptr, nullptr);
121 : }
122 : Handle<FixedArray> cache_array;
123 : int cache_length;
124 52239 : if (cache_type->IsMap()) {
125 9935 : Handle<Map> cache_map = Handle<Map>::cast(cache_type);
126 : Handle<DescriptorArray> descriptors(cache_map->instance_descriptors(),
127 9935 : isolate);
128 9935 : cache_length = cache_map->EnumLength();
129 16307 : if (cache_length && descriptors->HasEnumCache()) {
130 6372 : cache_array = handle(descriptors->GetEnumCache(), isolate);
131 : } else {
132 3563 : cache_array = isolate->factory()->empty_fixed_array();
133 : cache_length = 0;
134 : }
135 : } else {
136 42304 : cache_array = Handle<FixedArray>::cast(cache_type);
137 42304 : cache_length = cache_array->length();
138 42304 : cache_type = handle(Smi::FromInt(1), isolate);
139 : }
140 104478 : return MakeTriple(*cache_type, *cache_array, Smi::FromInt(cache_length));
141 : }
142 :
143 575322 : RUNTIME_FUNCTION(Runtime_ForInHasProperty) {
144 287661 : HandleScope scope(isolate);
145 : DCHECK_EQ(2, args.length());
146 575322 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
147 287661 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
148 : Handle<Object> result;
149 575322 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
150 : isolate, result, HasEnumerableProperty(isolate, receiver, key));
151 287616 : return isolate->heap()->ToBoolean(!result->IsUndefined(isolate));
152 : }
153 :
154 0 : RUNTIME_FUNCTION(Runtime_ForInFilter) {
155 0 : HandleScope scope(isolate);
156 : DCHECK_EQ(2, args.length());
157 0 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
158 0 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
159 0 : RETURN_RESULT_OR_FAILURE(isolate,
160 0 : HasEnumerableProperty(isolate, receiver, key));
161 : }
162 :
163 : } // namespace internal
164 : } // namespace v8
|