Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: src/prototype.h

Issue 1675223002: Mark maps having a hidden prototype rather than maps of hidden prototypes. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Addressed comment Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ppc/builtins-ppc.cc ('k') | src/runtime/runtime-debug.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_PROTOTYPE_H_ 5 #ifndef V8_PROTOTYPE_H_
6 #define V8_PROTOTYPE_H_ 6 #define V8_PROTOTYPE_H_
7 7
8 #include "src/isolate.h" 8 #include "src/isolate.h"
9 #include "src/objects.h" 9 #include "src/objects.h"
10 10
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 13
14 /** 14 /**
15 * A class to uniformly access the prototype of any Object and walk its 15 * A class to uniformly access the prototype of any Object and walk its
16 * prototype chain. 16 * prototype chain.
17 * 17 *
18 * The PrototypeIterator can either start at the prototype (default), or 18 * The PrototypeIterator can either start at the prototype (default), or
19 * include the receiver itself. If a PrototypeIterator is constructed for a 19 * include the receiver itself. If a PrototypeIterator is constructed for a
20 * Map, it will always start at the prototype. 20 * Map, it will always start at the prototype.
21 * 21 *
22 * The PrototypeIterator can either run to the null_value(), the first 22 * The PrototypeIterator can either run to the null_value(), the first
23 * non-hidden prototype, or a given object. 23 * non-hidden prototype, or a given object.
24 */ 24 */
25
25 class PrototypeIterator { 26 class PrototypeIterator {
26 public: 27 public:
27 enum WhereToStart { START_AT_RECEIVER, START_AT_PROTOTYPE }; 28 enum WhereToStart { START_AT_RECEIVER, START_AT_PROTOTYPE };
28 29
29 enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN }; 30 enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
30 31
31 const int kProxyPrototypeLimit = 100 * 1000; 32 const int kProxyPrototypeLimit = 100 * 1000;
32 33
33 PrototypeIterator(Isolate* isolate, Handle<Object> receiver, 34 PrototypeIterator(Isolate* isolate, Handle<JSReceiver> receiver,
34 WhereToStart where_to_start = START_AT_PROTOTYPE) 35 WhereToStart where_to_start = START_AT_PROTOTYPE,
35 : did_jump_to_prototype_chain_(false), 36 WhereToEnd where_to_end = END_AT_NULL)
36 object_(NULL), 37 : object_(NULL),
37 handle_(receiver), 38 handle_(receiver),
38 isolate_(isolate), 39 isolate_(isolate),
40 where_to_end_(where_to_end),
41 is_at_end_(false),
39 seen_proxies_(0) { 42 seen_proxies_(0) {
40 CHECK(!handle_.is_null()); 43 CHECK(!handle_.is_null());
41 if (where_to_start == START_AT_PROTOTYPE) { 44 if (where_to_start == START_AT_PROTOTYPE) Advance();
42 Advance();
43 }
44 } 45 }
45 46
46 PrototypeIterator(Isolate* isolate, Object* receiver, 47 PrototypeIterator(Isolate* isolate, JSReceiver* receiver,
47 WhereToStart where_to_start = START_AT_PROTOTYPE) 48 WhereToStart where_to_start = START_AT_PROTOTYPE,
48 : did_jump_to_prototype_chain_(false), 49 WhereToEnd where_to_end = END_AT_NULL)
49 object_(receiver), 50 : object_(receiver),
50 isolate_(isolate), 51 isolate_(isolate),
52 where_to_end_(where_to_end),
53 is_at_end_(false),
51 seen_proxies_(0) { 54 seen_proxies_(0) {
52 if (where_to_start == START_AT_PROTOTYPE) { 55 if (where_to_start == START_AT_PROTOTYPE) Advance();
53 Advance();
54 }
55 } 56 }
56 57
57 explicit PrototypeIterator(Map* receiver_map) 58 explicit PrototypeIterator(Map* receiver_map)
58 : did_jump_to_prototype_chain_(true), 59 : object_(receiver_map->prototype()),
59 object_(receiver_map->prototype()), 60 isolate_(receiver_map->GetIsolate()),
60 isolate_(receiver_map->GetIsolate()) {} 61 where_to_end_(END_AT_NULL),
62 is_at_end_(object_->IsNull()) {}
61 63
62 explicit PrototypeIterator(Handle<Map> receiver_map) 64 explicit PrototypeIterator(Handle<Map> receiver_map)
63 : did_jump_to_prototype_chain_(true), 65 : object_(NULL),
64 object_(NULL),
65 handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())), 66 handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())),
66 isolate_(receiver_map->GetIsolate()) {} 67 isolate_(receiver_map->GetIsolate()),
68 where_to_end_(END_AT_NULL),
69 is_at_end_(handle_->IsNull()) {}
67 70
68 ~PrototypeIterator() {} 71 ~PrototypeIterator() {}
69 72
70 bool HasAccess() const { 73 bool HasAccess() const {
71 // We can only perform access check in the handlified version of the 74 // We can only perform access check in the handlified version of the
72 // PrototypeIterator. 75 // PrototypeIterator.
73 DCHECK(!handle_.is_null()); 76 DCHECK(!handle_.is_null());
74 if (handle_->IsAccessCheckNeeded()) { 77 if (handle_->IsAccessCheckNeeded()) {
75 return isolate_->MayAccess(handle(isolate_->context()), 78 return isolate_->MayAccess(handle(isolate_->context()),
76 Handle<JSObject>::cast(handle_)); 79 Handle<JSObject>::cast(handle_));
77 } 80 }
78 return true; 81 return true;
79 } 82 }
80 83
81 template <typename T = Object> 84 template <typename T = Object>
82 T* GetCurrent() const { 85 T* GetCurrent() const {
83 DCHECK(handle_.is_null()); 86 DCHECK(handle_.is_null());
84 return T::cast(object_); 87 return T::cast(object_);
85 } 88 }
86 89
87 template <typename T = Object> 90 template <typename T = Object>
88 static Handle<T> GetCurrent(const PrototypeIterator& iterator) { 91 static Handle<T> GetCurrent(const PrototypeIterator& iterator) {
89 DCHECK(!iterator.handle_.is_null()); 92 DCHECK(!iterator.handle_.is_null());
90 DCHECK(iterator.object_ == NULL); 93 DCHECK(iterator.object_ == NULL);
91 return Handle<T>::cast(iterator.handle_); 94 return Handle<T>::cast(iterator.handle_);
92 } 95 }
93 96
94 void Advance() { 97 void Advance() {
95 if (handle_.is_null() && object_->IsJSProxy()) { 98 if (handle_.is_null() && object_->IsJSProxy()) {
96 did_jump_to_prototype_chain_ = true; 99 is_at_end_ = true;
97 object_ = isolate_->heap()->null_value(); 100 object_ = isolate_->heap()->null_value();
98 return; 101 return;
99 } else if (!handle_.is_null() && handle_->IsJSProxy()) { 102 } else if (!handle_.is_null() && handle_->IsJSProxy()) {
100 did_jump_to_prototype_chain_ = true; 103 is_at_end_ = true;
101 handle_ = handle(isolate_->heap()->null_value(), isolate_); 104 handle_ = isolate_->factory()->null_value();
102 return; 105 return;
103 } 106 }
104 AdvanceIgnoringProxies(); 107 AdvanceIgnoringProxies();
105 } 108 }
106 109
107 void AdvanceIgnoringProxies() { 110 void AdvanceIgnoringProxies() {
108 if (!did_jump_to_prototype_chain_) { 111 Object* object = handle_.is_null() ? object_ : *handle_;
109 did_jump_to_prototype_chain_ = true; 112 Map* map = HeapObject::cast(object)->map();
110 if (handle_.is_null()) { 113
111 object_ = object_->GetRootMap(isolate_)->prototype(); 114 Object* prototype = map->prototype();
112 } else { 115 is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN
113 handle_ = handle(handle_->GetRootMap(isolate_)->prototype(), isolate_); 116 ? !map->has_hidden_prototype()
114 } 117 : prototype->IsNull();
118
119 if (handle_.is_null()) {
120 object_ = prototype;
115 } else { 121 } else {
116 if (handle_.is_null()) { 122 handle_ = handle(prototype, isolate_);
117 object_ = HeapObject::cast(object_)->map()->prototype();
118 } else {
119 handle_ =
120 handle(HeapObject::cast(*handle_)->map()->prototype(), isolate_);
121 }
122 } 123 }
123 } 124 }
124 125
125 // Returns false iff a call to JSProxy::GetPrototype throws. 126 // Returns false iff a call to JSProxy::GetPrototype throws.
126 // TODO(neis): This should probably replace Advance(). 127 // TODO(neis): This should probably replace Advance().
127 bool AdvanceFollowingProxies() { 128 bool AdvanceFollowingProxies() {
128 DCHECK(!(handle_.is_null() && object_->IsJSProxy())); 129 DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
129 if (!HasAccess()) { 130 if (!HasAccess()) {
130 // Abort the lookup if we do not have access to the current object. 131 // Abort the lookup if we do not have access to the current object.
131 handle_ = isolate_->factory()->null_value(); 132 handle_ = isolate_->factory()->null_value();
133 is_at_end_ = true;
132 return true; 134 return true;
133 } 135 }
134 if (handle_.is_null() || !handle_->IsJSProxy()) { 136 if (handle_.is_null() || !handle_->IsJSProxy()) {
135 AdvanceIgnoringProxies(); 137 AdvanceIgnoringProxies();
136 return true; 138 return true;
137 } 139 }
138 // Due to possible __proto__ recursion limit the number of Proxies 140 // Due to possible __proto__ recursion limit the number of Proxies
139 // we visit to an arbitrarily chosen large number. 141 // we visit to an arbitrarily chosen large number.
140 seen_proxies_++; 142 seen_proxies_++;
141 if (seen_proxies_ > kProxyPrototypeLimit) { 143 if (seen_proxies_ > kProxyPrototypeLimit) {
142 isolate_->Throw( 144 isolate_->Throw(
143 *isolate_->factory()->NewRangeError(MessageTemplate::kStackOverflow)); 145 *isolate_->factory()->NewRangeError(MessageTemplate::kStackOverflow));
144 return false; 146 return false;
145 } 147 }
146 did_jump_to_prototype_chain_ = true;
147 MaybeHandle<Object> proto = 148 MaybeHandle<Object> proto =
148 JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_)); 149 JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
149 return proto.ToHandle(&handle_); 150 if (!proto.ToHandle(&handle_)) return false;
151 is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull();
152 return true;
150 } 153 }
151 154
152 bool IsAtEnd(WhereToEnd where_to_end = END_AT_NULL) const { 155 bool IsAtEnd() const { return is_at_end_; }
153 if (handle_.is_null()) {
154 return object_->IsNull() ||
155 (did_jump_to_prototype_chain_ &&
156 where_to_end == END_AT_NON_HIDDEN &&
157 !HeapObject::cast(object_)->map()->is_hidden_prototype());
158 } else {
159 return handle_->IsNull() ||
160 (did_jump_to_prototype_chain_ &&
161 where_to_end == END_AT_NON_HIDDEN &&
162 !Handle<HeapObject>::cast(handle_)->map()->is_hidden_prototype());
163 }
164 }
165
166 bool IsAtEnd(Object* final_object) {
167 DCHECK(handle_.is_null());
168 return object_->IsNull() || object_ == final_object;
169 }
170
171 bool IsAtEnd(Handle<Object> final_object) {
172 DCHECK(!handle_.is_null());
173 return handle_->IsNull() || *handle_ == *final_object;
174 }
175 156
176 private: 157 private:
177 bool did_jump_to_prototype_chain_;
178 Object* object_; 158 Object* object_;
179 Handle<Object> handle_; 159 Handle<Object> handle_;
180 Isolate* isolate_; 160 Isolate* isolate_;
161 WhereToEnd where_to_end_;
162 bool is_at_end_;
181 int seen_proxies_; 163 int seen_proxies_;
182 164
183 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator); 165 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
184 }; 166 };
185 167
186 168
187 } // namespace internal 169 } // namespace internal
188 170
189 } // namespace v8 171 } // namespace v8
190 172
191 #endif // V8_PROTOTYPE_H_ 173 #endif // V8_PROTOTYPE_H_
OLDNEW
« no previous file with comments | « src/ppc/builtins-ppc.cc ('k') | src/runtime/runtime-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698