blob: 032d9b6b347614422c5e42af284c5be8d650e744 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 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_H_
6#define V8_PROTOTYPE_H_
7
8#include "src/isolate.h"
9#include "src/objects.h"
10
11namespace v8 {
12namespace internal {
13
14/**
15 * A class to uniformly access the prototype of any Object and walk its
16 * prototype chain.
17 *
18 * The PrototypeIterator can either start at the prototype (default), or
19 * include the receiver itself. If a PrototypeIterator is constructed for a
20 * Map, it will always start at the prototype.
21 *
22 * The PrototypeIterator can either run to the null_value(), the first
23 * non-hidden prototype, or a given object.
24 */
Ben Murdoch097c5b22016-05-18 11:27:45 +010025
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026class PrototypeIterator {
27 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
29
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 const int kProxyPrototypeLimit = 100 * 1000;
31
Ben Murdoch097c5b22016-05-18 11:27:45 +010032 PrototypeIterator(Isolate* isolate, Handle<JSReceiver> receiver,
Ben Murdoch61f157c2016-09-16 13:49:30 +010033 WhereToStart where_to_start = kStartAtPrototype,
Ben Murdoch097c5b22016-05-18 11:27:45 +010034 WhereToEnd where_to_end = END_AT_NULL)
35 : object_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 handle_(receiver),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 isolate_(isolate),
Ben Murdoch097c5b22016-05-18 11:27:45 +010038 where_to_end_(where_to_end),
39 is_at_end_(false),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000040 seen_proxies_(0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041 CHECK(!handle_.is_null());
Ben Murdoch61f157c2016-09-16 13:49:30 +010042 if (where_to_start == kStartAtPrototype) Advance();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044
Ben Murdoch097c5b22016-05-18 11:27:45 +010045 PrototypeIterator(Isolate* isolate, JSReceiver* receiver,
Ben Murdoch61f157c2016-09-16 13:49:30 +010046 WhereToStart where_to_start = kStartAtPrototype,
Ben Murdoch097c5b22016-05-18 11:27:45 +010047 WhereToEnd where_to_end = END_AT_NULL)
48 : object_(receiver),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 isolate_(isolate),
Ben Murdoch097c5b22016-05-18 11:27:45 +010050 where_to_end_(where_to_end),
51 is_at_end_(false),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052 seen_proxies_(0) {
Ben Murdoch61f157c2016-09-16 13:49:30 +010053 if (where_to_start == kStartAtPrototype) Advance();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056 explicit PrototypeIterator(Map* receiver_map)
Ben Murdoch097c5b22016-05-18 11:27:45 +010057 : object_(receiver_map->prototype()),
58 isolate_(receiver_map->GetIsolate()),
59 where_to_end_(END_AT_NULL),
Ben Murdoch61f157c2016-09-16 13:49:30 +010060 is_at_end_(object_->IsNull(isolate_)),
61 seen_proxies_(0) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 explicit PrototypeIterator(Handle<Map> receiver_map)
Ben Murdoch097c5b22016-05-18 11:27:45 +010064 : object_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065 handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())),
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 isolate_(receiver_map->GetIsolate()),
67 where_to_end_(END_AT_NULL),
Ben Murdoch61f157c2016-09-16 13:49:30 +010068 is_at_end_(handle_->IsNull(isolate_)),
69 seen_proxies_(0) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 ~PrototypeIterator() {}
72
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 bool HasAccess() const {
74 // We can only perform access check in the handlified version of the
75 // PrototypeIterator.
76 DCHECK(!handle_.is_null());
77 if (handle_->IsAccessCheckNeeded()) {
78 return isolate_->MayAccess(handle(isolate_->context()),
79 Handle<JSObject>::cast(handle_));
80 }
81 return true;
82 }
83
84 template <typename T = Object>
85 T* GetCurrent() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 DCHECK(handle_.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 return T::cast(object_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089
90 template <typename T = Object>
91 static Handle<T> GetCurrent(const PrototypeIterator& iterator) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092 DCHECK(!iterator.handle_.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000093 DCHECK(iterator.object_ == NULL);
94 return Handle<T>::cast(iterator.handle_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097 void Advance() {
98 if (handle_.is_null() && object_->IsJSProxy()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010099 is_at_end_ = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 object_ = isolate_->heap()->null_value();
101 return;
102 } else if (!handle_.is_null() && handle_->IsJSProxy()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100103 is_at_end_ = true;
104 handle_ = isolate_->factory()->null_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 return;
106 }
107 AdvanceIgnoringProxies();
108 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 void AdvanceIgnoringProxies() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100111 Object* object = handle_.is_null() ? object_ : *handle_;
112 Map* map = HeapObject::cast(object)->map();
113
114 Object* prototype = map->prototype();
115 is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN
116 ? !map->has_hidden_prototype()
Ben Murdoch61f157c2016-09-16 13:49:30 +0100117 : prototype->IsNull(isolate_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100118
119 if (handle_.is_null()) {
120 object_ = prototype;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100122 handle_ = handle(prototype, isolate_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 }
124 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125
126 // Returns false iff a call to JSProxy::GetPrototype throws.
127 // TODO(neis): This should probably replace Advance().
Ben Murdochda12d292016-06-02 14:46:10 +0100128 MUST_USE_RESULT bool AdvanceFollowingProxies() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
130 if (!HasAccess()) {
131 // Abort the lookup if we do not have access to the current object.
132 handle_ = isolate_->factory()->null_value();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100133 is_at_end_ = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 return true;
135 }
Ben Murdochda12d292016-06-02 14:46:10 +0100136 return AdvanceFollowingProxiesIgnoringAccessChecks();
137 }
138
139 MUST_USE_RESULT bool AdvanceFollowingProxiesIgnoringAccessChecks() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 if (handle_.is_null() || !handle_->IsJSProxy()) {
141 AdvanceIgnoringProxies();
142 return true;
143 }
Ben Murdochda12d292016-06-02 14:46:10 +0100144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 // Due to possible __proto__ recursion limit the number of Proxies
146 // we visit to an arbitrarily chosen large number.
147 seen_proxies_++;
148 if (seen_proxies_ > kProxyPrototypeLimit) {
149 isolate_->Throw(
150 *isolate_->factory()->NewRangeError(MessageTemplate::kStackOverflow));
151 return false;
152 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 MaybeHandle<Object> proto =
154 JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100155 if (!proto.ToHandle(&handle_)) return false;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100156 is_at_end_ =
157 where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100158 return true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 }
160
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161 bool IsAtEnd() const { return is_at_end_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000162
163 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 Object* object_;
165 Handle<Object> handle_;
166 Isolate* isolate_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100167 WhereToEnd where_to_end_;
168 bool is_at_end_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169 int seen_proxies_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170
171 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
172};
173
174
175} // namespace internal
176
177} // namespace v8
178
179#endif // V8_PROTOTYPE_H_