• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_OBJECTS_PROTOTYPE_INL_H_
6 #define V8_OBJECTS_PROTOTYPE_INL_H_
7 
8 #include "src/objects/prototype.h"
9 
10 #include "src/handles/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 
PrototypeIterator(Isolate * isolate,Handle<JSReceiver> receiver,WhereToStart where_to_start,WhereToEnd where_to_end)17 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       seen_proxies_(0) {
26   CHECK(!handle_.is_null());
27   if (where_to_start == kStartAtPrototype) Advance();
28 }
29 
PrototypeIterator(Isolate * isolate,JSReceiver receiver,WhereToStart where_to_start,WhereToEnd where_to_end)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       seen_proxies_(0) {
38   if (where_to_start == kStartAtPrototype) Advance();
39 }
40 
PrototypeIterator(Isolate * isolate,Map receiver_map,WhereToEnd where_to_end)41 PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map,
42                                      WhereToEnd where_to_end)
43     : isolate_(isolate),
44       object_(receiver_map.GetPrototypeChainRootMap(isolate_).prototype()),
45       where_to_end_(where_to_end),
46       is_at_end_(object_.IsNull(isolate_)),
47       seen_proxies_(0) {
48   if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
49     DCHECK(object_.IsJSReceiver());
50     Map map = JSReceiver::cast(object_).map();
51     is_at_end_ = !map.IsJSGlobalProxyMap();
52   }
53 }
54 
PrototypeIterator(Isolate * isolate,Handle<Map> receiver_map,WhereToEnd where_to_end)55 PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map,
56                                      WhereToEnd where_to_end)
57     : isolate_(isolate),
58       handle_(receiver_map->GetPrototypeChainRootMap(isolate_).prototype(),
59               isolate_),
60       where_to_end_(where_to_end),
61       is_at_end_(handle_->IsNull(isolate_)),
62       seen_proxies_(0) {
63   if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
64     DCHECK(handle_->IsJSReceiver());
65     Map map = JSReceiver::cast(*handle_).map();
66     is_at_end_ = !map.IsJSGlobalProxyMap();
67   }
68 }
69 
HasAccess()70 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   if (handle_->IsAccessCheckNeeded()) {
75     return isolate_->MayAccess(handle(isolate_->context(), isolate_),
76                                Handle<JSObject>::cast(handle_));
77   }
78   return true;
79 }
80 
Advance()81 void PrototypeIterator::Advance() {
82   if (handle_.is_null() && object_.IsJSProxy()) {
83     is_at_end_ = true;
84     object_ = ReadOnlyRoots(isolate_).null_value();
85     return;
86   } else if (!handle_.is_null() && handle_->IsJSProxy()) {
87     is_at_end_ = true;
88     handle_ = isolate_->factory()->null_value();
89     return;
90   }
91   AdvanceIgnoringProxies();
92 }
93 
AdvanceIgnoringProxies()94 void PrototypeIterator::AdvanceIgnoringProxies() {
95   Object object = handle_.is_null() ? object_ : *handle_;
96   Map map = HeapObject::cast(object).map();
97 
98   HeapObject prototype = map.prototype();
99   is_at_end_ =
100       prototype.IsNull(isolate_) ||
101       (where_to_end_ == END_AT_NON_HIDDEN && !map.IsJSGlobalProxyMap());
102 
103   if (handle_.is_null()) {
104     object_ = prototype;
105   } else {
106     handle_ = handle(prototype, isolate_);
107   }
108 }
109 
AdvanceFollowingProxies()110 V8_WARN_UNUSED_RESULT bool PrototypeIterator::AdvanceFollowingProxies() {
111   DCHECK(!(handle_.is_null() && object_.IsJSProxy()));
112   if (!HasAccess()) {
113     // Abort the lookup if we do not have access to the current object.
114     handle_ = isolate_->factory()->null_value();
115     is_at_end_ = true;
116     return true;
117   }
118   return AdvanceFollowingProxiesIgnoringAccessChecks();
119 }
120 
121 V8_WARN_UNUSED_RESULT bool
AdvanceFollowingProxiesIgnoringAccessChecks()122 PrototypeIterator::AdvanceFollowingProxiesIgnoringAccessChecks() {
123   if (handle_.is_null() || !handle_->IsJSProxy()) {
124     AdvanceIgnoringProxies();
125     return true;
126   }
127 
128   // Due to possible __proto__ recursion limit the number of Proxies
129   // we visit to an arbitrarily chosen large number.
130   seen_proxies_++;
131   if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
132     isolate_->StackOverflow();
133     return false;
134   }
135   MaybeHandle<HeapObject> proto =
136       JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
137   if (!proto.ToHandle(&handle_)) return false;
138   is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
139   return true;
140 }
141 
142 }  // namespace internal
143 }  // namespace v8
144 
145 #endif  // V8_OBJECTS_PROTOTYPE_INL_H_
146