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 6305581 : 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 22469944 : seen_proxies_(0) {
26 11234972 : CHECK(!handle_.is_null());
27 6305581 : if (where_to_start == kStartAtPrototype) Advance();
28 6305584 : }
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 2339338 : seen_proxies_(0) {
38 985261 : if (where_to_start == kStartAtPrototype) Advance();
39 : }
40 :
41 62130 : PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map,
42 : WhereToEnd where_to_end)
43 : : isolate_(isolate),
44 124260 : object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
45 : where_to_end_(where_to_end),
46 62130 : is_at_end_(object_->IsNull(isolate_)),
47 248520 : seen_proxies_(0) {
48 62130 : 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 62130 : }
54 :
55 1798678 : PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map,
56 : WhereToEnd where_to_end)
57 : : isolate_(isolate),
58 3597348 : handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
59 : isolate_),
60 : where_to_end_(where_to_end),
61 1798670 : is_at_end_(handle_->IsNull(isolate_)),
62 5396018 : seen_proxies_(0) {
63 1798670 : 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 1798670 : }
69 :
70 6975810 : 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 6975810 : 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 9295469 : void PrototypeIterator::Advance() {
82 10921058 : if (handle_.is_null() && object_->IsJSProxy()) {
83 1429 : is_at_end_ = true;
84 2858 : object_ = ReadOnlyRoots(isolate_).null_value();
85 1429 : return;
86 16963911 : } else if (!handle_.is_null() && handle_->IsJSProxy()) {
87 760 : is_at_end_ = true;
88 1520 : handle_ = isolate_->factory()->null_value();
89 760 : return;
90 : }
91 9293280 : AdvanceIgnoringProxies();
92 : }
93 :
94 14894972 : void PrototypeIterator::AdvanceIgnoringProxies() {
95 14894972 : Object object = handle_.is_null() ? object_ : *handle_;
96 : Map map = HeapObject::cast(object)->map();
97 :
98 : HeapObject prototype = map->prototype();
99 14894972 : is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN ? !map->has_hidden_prototype()
100 34539019 : : prototype->IsNull(isolate_);
101 :
102 14894972 : if (handle_.is_null()) {
103 1637549 : object_ = prototype;
104 : } else {
105 26514854 : handle_ = handle(prototype, isolate_);
106 : }
107 14894980 : }
108 :
109 6975810 : V8_WARN_UNUSED_RESULT bool PrototypeIterator::AdvanceFollowingProxies() {
110 : DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
111 6975810 : 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 6975639 : return AdvanceFollowingProxiesIgnoringAccessChecks();
118 : }
119 :
120 : V8_WARN_UNUSED_RESULT bool
121 9218744 : PrototypeIterator::AdvanceFollowingProxiesIgnoringAccessChecks() {
122 18437488 : if (handle_.is_null() || !handle_->IsJSProxy()) {
123 5486902 : AdvanceIgnoringProxies();
124 5486902 : 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 3731842 : seen_proxies_++;
130 3731842 : if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
131 36 : isolate_->StackOverflow();
132 36 : return false;
133 : }
134 : MaybeHandle<HeapObject> proto =
135 3731806 : JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
136 7463612 : if (!proto.ToHandle(&handle_)) return false;
137 7375664 : is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
138 3688066 : return true;
139 : }
140 :
141 : } // namespace internal
142 : } // namespace v8
143 :
144 : #endif // V8_PROTOTYPE_INL_H_
|