Line data Source code
1 : // Copyright 2018 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 : #ifndef V8_PROTOTYPE_INL_H_
6 : #define V8_PROTOTYPE_INL_H_
7 :
8 : #include "src/prototype.h"
9 :
10 : #include "src/handles-inl.h"
11 : #include "src/objects/js-proxy.h"
12 : #include "src/objects/map-inl.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 6270273 : PrototypeIterator::PrototypeIterator(Isolate* isolate,
18 : Handle<JSReceiver> receiver,
19 : WhereToStart where_to_start,
20 : WhereToEnd where_to_end)
21 : : isolate_(isolate),
22 : handle_(receiver),
23 : where_to_end_(where_to_end),
24 : is_at_end_(false),
25 22379416 : seen_proxies_(0) {
26 11189708 : CHECK(!handle_.is_null());
27 6270273 : if (where_to_start == kStartAtPrototype) Advance();
28 6270278 : }
29 :
30 : PrototypeIterator::PrototypeIterator(Isolate* isolate, JSReceiver receiver,
31 : WhereToStart where_to_start,
32 : WhereToEnd where_to_end)
33 : : isolate_(isolate),
34 : object_(receiver),
35 : where_to_end_(where_to_end),
36 : is_at_end_(false),
37 2336636 : seen_proxies_(0) {
38 984132 : if (where_to_start == kStartAtPrototype) Advance();
39 : }
40 :
41 61567 : PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map,
42 : WhereToEnd where_to_end)
43 : : isolate_(isolate),
44 123134 : object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
45 : where_to_end_(where_to_end),
46 61567 : is_at_end_(object_->IsNull(isolate_)),
47 246268 : seen_proxies_(0) {
48 61567 : if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
49 : DCHECK(object_->IsJSReceiver());
50 : Map map = JSReceiver::cast(object_)->map();
51 0 : is_at_end_ = !map->has_hidden_prototype();
52 : }
53 61567 : }
54 :
55 1816434 : PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map,
56 : WhereToEnd where_to_end)
57 : : isolate_(isolate),
58 3632871 : handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
59 : isolate_),
60 : where_to_end_(where_to_end),
61 1816437 : is_at_end_(handle_->IsNull(isolate_)),
62 5449308 : seen_proxies_(0) {
63 1816437 : if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
64 : DCHECK(handle_->IsJSReceiver());
65 : Map map = JSReceiver::cast(*handle_)->map();
66 0 : is_at_end_ = !map->has_hidden_prototype();
67 : }
68 1816437 : }
69 :
70 6967179 : bool PrototypeIterator::HasAccess() const {
71 : // We can only perform access check in the handlified version of the
72 : // PrototypeIterator.
73 : DCHECK(!handle_.is_null());
74 6967179 : if (handle_->IsAccessCheckNeeded()) {
75 382 : return isolate_->MayAccess(handle(isolate_->context(), isolate_),
76 191 : Handle<JSObject>::cast(handle_));
77 : }
78 : return true;
79 : }
80 :
81 9249145 : void PrototypeIterator::Advance() {
82 10871439 : if (handle_.is_null() && object_->IsJSProxy()) {
83 1429 : is_at_end_ = true;
84 2858 : object_ = ReadOnlyRoots(isolate_).null_value();
85 1429 : return;
86 16874555 : } else if (!handle_.is_null() && handle_->IsJSProxy()) {
87 768 : is_at_end_ = true;
88 1536 : handle_ = isolate_->factory()->null_value();
89 768 : return;
90 : }
91 9246948 : AdvanceIgnoringProxies();
92 : }
93 :
94 14843386 : void PrototypeIterator::AdvanceIgnoringProxies() {
95 14843386 : Object object = handle_.is_null() ? object_ : *handle_;
96 : Map map = HeapObject::cast(object)->map();
97 :
98 : Object prototype = map->prototype();
99 14843386 : is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN ? !map->has_hidden_prototype()
100 34432346 : : prototype->IsNull(isolate_);
101 :
102 14843386 : if (handle_.is_null()) {
103 1634053 : object_ = prototype;
104 : } else {
105 26418682 : handle_ = handle(prototype, isolate_);
106 : }
107 14843402 : }
108 :
109 6967179 : V8_WARN_UNUSED_RESULT bool PrototypeIterator::AdvanceFollowingProxies() {
110 : DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
111 6967179 : if (!HasAccess()) {
112 : // Abort the lookup if we do not have access to the current object.
113 342 : handle_ = isolate_->factory()->null_value();
114 171 : is_at_end_ = true;
115 171 : return true;
116 : }
117 6967008 : return AdvanceFollowingProxiesIgnoringAccessChecks();
118 : }
119 :
120 : V8_WARN_UNUSED_RESULT bool
121 9210509 : PrototypeIterator::AdvanceFollowingProxiesIgnoringAccessChecks() {
122 18421018 : if (handle_.is_null() || !handle_->IsJSProxy()) {
123 5481835 : AdvanceIgnoringProxies();
124 5481835 : return true;
125 : }
126 :
127 : // Due to possible __proto__ recursion limit the number of Proxies
128 : // we visit to an arbitrarily chosen large number.
129 3728674 : seen_proxies_++;
130 3728674 : if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
131 36 : isolate_->StackOverflow();
132 36 : return false;
133 : }
134 : MaybeHandle<Object> proto =
135 3728638 : JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
136 3728638 : if (!proto.ToHandle(&handle_)) return false;
137 7375556 : is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
138 3688012 : return true;
139 : }
140 :
141 : } // namespace internal
142 : } // namespace v8
143 :
144 : #endif // V8_PROTOTYPE_INL_H_
|