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 59535 : MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) {
24 : Isolate* const isolate = receiver->GetIsolate();
25 59535 : 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 59535 : if (!accumulator.is_receiver_simple_enum()) {
32 : Handle<FixedArray> keys;
33 113334 : 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 56574 : if (!accumulator.is_receiver_simple_enum()) return keys;
38 : }
39 10990 : 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 245569 : MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
45 : Handle<JSReceiver> receiver,
46 : Handle<Object> key) {
47 245569 : bool success = false;
48 : Maybe<PropertyAttributes> result = Just(ABSENT);
49 : LookupIterator it =
50 245569 : LookupIterator::PropertyOrElement(isolate, receiver, key, &success);
51 245569 : if (!success) return isolate->factory()->undefined_value();
52 244001 : for (; it.IsFound(); it.Next()) {
53 489552 : 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 751 : result = JSProxy::GetPropertyAttributes(&it);
60 751 : if (result.IsNothing()) return MaybeHandle<Object>();
61 721 : if (result.FromJust() == ABSENT) {
62 : // Continue lookup on the proxy's prototype.
63 82 : Handle<JSProxy> proxy = it.GetHolder<JSProxy>();
64 : Handle<Object> prototype;
65 164 : ASSIGN_RETURN_ON_EXCEPTION(isolate, prototype,
66 : JSProxy::GetPrototype(proxy), Object);
67 82 : if (prototype->IsNull(isolate)) {
68 10 : return isolate->factory()->undefined_value();
69 : }
70 : // We already have a stack-check in JSProxy::GetPrototype.
71 : return HasEnumerableProperty(
72 72 : isolate, Handle<JSReceiver>::cast(prototype), key);
73 639 : } else if (result.FromJust() & DONT_ENUM) {
74 54 : return isolate->factory()->undefined_value();
75 : } else {
76 585 : return it.GetName();
77 : }
78 : }
79 : case LookupIterator::INTERCEPTOR: {
80 240249 : result = JSObject::GetPropertyAttributesWithInterceptor(&it);
81 240249 : if (result.IsNothing()) return MaybeHandle<Object>();
82 240249 : if (result.FromJust() != ABSENT) return it.GetName();
83 : continue;
84 : }
85 : case LookupIterator::ACCESS_CHECK: {
86 3967 : 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 0 : return isolate->factory()->undefined_value();
91 : }
92 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
93 : // TypedArray out-of-bounds access.
94 0 : return isolate->factory()->undefined_value();
95 : case LookupIterator::ACCESSOR:
96 : case LookupIterator::DATA:
97 244585 : return it.GetName();
98 : }
99 : }
100 18 : return isolate->factory()->undefined_value();
101 : }
102 :
103 : } // namespace
104 :
105 :
106 119070 : RUNTIME_FUNCTION(Runtime_ForInEnumerate) {
107 59535 : HandleScope scope(isolate);
108 : DCHECK_EQ(1, args.length());
109 119070 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
110 178605 : RETURN_RESULT_OR_FAILURE(isolate, Enumerate(receiver));
111 : }
112 :
113 :
114 490994 : RUNTIME_FUNCTION(Runtime_ForInHasProperty) {
115 245497 : HandleScope scope(isolate);
116 : DCHECK_EQ(2, args.length());
117 490994 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
118 245497 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
119 : Handle<Object> result;
120 490994 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
121 : isolate, result, HasEnumerableProperty(isolate, receiver, key));
122 245467 : return isolate->heap()->ToBoolean(!result->IsUndefined(isolate));
123 : }
124 :
125 : } // namespace internal
126 : } // namespace v8
|