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/map-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 10486692 : PrototypeIterator::PrototypeIterator(Isolate* isolate,
17 : Handle<JSReceiver> receiver,
18 : WhereToStart where_to_start,
19 : WhereToEnd where_to_end)
20 : : isolate_(isolate),
21 : handle_(receiver),
22 : where_to_end_(where_to_end),
23 : is_at_end_(false),
24 20973384 : seen_proxies_(0) {
25 10486692 : CHECK(!handle_.is_null());
26 10486692 : if (where_to_start == kStartAtPrototype) Advance();
27 10486694 : }
28 :
29 : PrototypeIterator::PrototypeIterator(Isolate* isolate, JSReceiver receiver,
30 : WhereToStart where_to_start,
31 : WhereToEnd where_to_end)
32 : : isolate_(isolate),
33 : object_(receiver),
34 : where_to_end_(where_to_end),
35 : is_at_end_(false),
36 2339972 : seen_proxies_(0) {
37 985691 : if (where_to_start == kStartAtPrototype) Advance();
38 : }
39 :
40 59604 : PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map,
41 : WhereToEnd where_to_end)
42 : : isolate_(isolate),
43 119208 : object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
44 : where_to_end_(where_to_end),
45 59604 : is_at_end_(object_->IsNull(isolate_)),
46 238416 : seen_proxies_(0) {
47 59604 : if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
48 : DCHECK(object_->IsJSReceiver());
49 0 : Map map = JSReceiver::cast(object_)->map();
50 0 : is_at_end_ = !map->has_hidden_prototype();
51 : }
52 59604 : }
53 :
54 1734989 : PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map,
55 : WhereToEnd where_to_end)
56 : : isolate_(isolate),
57 3469990 : handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
58 : isolate_),
59 : where_to_end_(where_to_end),
60 5204994 : is_at_end_(handle_->IsNull(isolate_)),
61 10409972 : seen_proxies_(0) {
62 1734998 : if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
63 : DCHECK(handle_->IsJSReceiver());
64 0 : Map map = JSReceiver::cast(*handle_)->map();
65 0 : is_at_end_ = !map->has_hidden_prototype();
66 : }
67 1734998 : }
68 :
69 6962015 : bool PrototypeIterator::HasAccess() const {
70 : // We can only perform access check in the handlified version of the
71 : // PrototypeIterator.
72 : DCHECK(!handle_.is_null());
73 13924030 : if (handle_->IsAccessCheckNeeded()) {
74 : return isolate_->MayAccess(handle(isolate_->context(), isolate_),
75 406 : Handle<JSObject>::cast(handle_));
76 : }
77 : return true;
78 : }
79 :
80 8308559 : void PrototypeIterator::Advance() {
81 9927560 : if (handle_.is_null() && object_->IsJSProxy()) {
82 1433 : is_at_end_ = true;
83 2866 : object_ = ReadOnlyRoots(isolate_).null_value();
84 1433 : return;
85 21686352 : } else if (!handle_.is_null() && handle_->IsJSProxy()) {
86 728 : is_at_end_ = true;
87 1456 : handle_ = isolate_->factory()->null_value();
88 728 : return;
89 : }
90 8306439 : AdvanceIgnoringProxies();
91 : }
92 :
93 13811853 : void PrototypeIterator::AdvanceIgnoringProxies() {
94 13811853 : Object object = handle_.is_null() ? object_ : *handle_;
95 13811849 : Map map = HeapObject::cast(object)->map();
96 :
97 13811849 : Object prototype = map->prototype();
98 18473208 : is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN ? !map->has_hidden_prototype()
99 32285070 : : prototype->IsNull(isolate_);
100 :
101 13811861 : if (handle_.is_null()) {
102 1630492 : object_ = prototype;
103 : } else {
104 24362740 : handle_ = handle(prototype, isolate_);
105 : }
106 13811863 : }
107 :
108 6962015 : V8_WARN_UNUSED_RESULT bool PrototypeIterator::AdvanceFollowingProxies() {
109 : DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
110 6962015 : if (!HasAccess()) {
111 : // Abort the lookup if we do not have access to the current object.
112 366 : handle_ = isolate_->factory()->null_value();
113 183 : is_at_end_ = true;
114 183 : return true;
115 : }
116 6961832 : return AdvanceFollowingProxiesIgnoringAccessChecks();
117 : }
118 :
119 : V8_WARN_UNUSED_RESULT bool
120 9107732 : PrototypeIterator::AdvanceFollowingProxiesIgnoringAccessChecks() {
121 27323196 : if (handle_.is_null() || !handle_->IsJSProxy()) {
122 5391215 : AdvanceIgnoringProxies();
123 5391215 : return true;
124 : }
125 :
126 : // Due to possible __proto__ recursion limit the number of Proxies
127 : // we visit to an arbitrarily chosen large number.
128 3716517 : seen_proxies_++;
129 3716517 : if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
130 36 : isolate_->StackOverflow();
131 36 : return false;
132 : }
133 : MaybeHandle<Object> proto =
134 3716481 : JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
135 7432962 : if (!proto.ToHandle(&handle_)) return false;
136 11063130 : is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
137 : return true;
138 : }
139 :
140 : } // namespace internal
141 : } // namespace v8
142 :
143 : #endif // V8_PROTOTYPE_INL_H_
|