| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef V8_PROTOTYPE_ITERATOR_H_ |
| 6 #define V8_PROTOTYPE_ITERATOR_H_ |
| 7 |
| 8 // This file defines an iterator that should be used to iterate over an |
| 9 // object's prototype chain. The iterator template can be specialized to |
| 10 // handle all common variations of iterating over the prototype chain, |
| 11 // and at the same time makes sure that security interceptors are honored. |
| 12 // |
| 13 // The iterator can also be used to look up just the prototype. |
| 14 // |
| 15 // The iterator should always be used unless it is safe to skip the security |
| 16 // interceptors, e.g., when all objects on the prototype chain are from the |
| 17 // same context. |
| 18 |
| 19 #include "src/v8.h" |
| 20 |
| 21 #include "src/base/macros.h" |
| 22 |
| 23 namespace v8 { |
| 24 namespace internal { |
| 25 |
| 26 /** |
| 27 * Whether to walk the prototype chain based on the map, or by using a switch |
| 28 * over the type. The latter will also work for non-JSReceiver prototypes but |
| 29 * is more expensive. |
| 30 */ |
| 31 enum WalkType { MAP_BASED_WALK, TYPE_BASED_WALK }; |
| 32 |
| 33 |
| 34 /** |
| 35 * Where to stop the chain walk: either at the null value, a given object, or |
| 36 * the first non-hidden prototype. |
| 37 */ |
| 38 enum WhereToEnd { END_AT_NULL_VALUE, END_AT_GIVEN_OBJECT, END_AT_NON_HIDDEN }; |
| 39 |
| 40 |
| 41 /** |
| 42 * How the iterator stores the object. |
| 43 */ |
| 44 enum StorageType { STORE_AS_POINTER, STORE_AS_HANDLE }; |
| 45 |
| 46 |
| 47 template <int storage_type> |
| 48 struct ObjectStorageType; |
| 49 |
| 50 |
| 51 template <> |
| 52 struct ObjectStorageType<STORE_AS_POINTER> { |
| 53 typedef Object* storage_type; |
| 54 }; |
| 55 |
| 56 |
| 57 template <> |
| 58 struct ObjectStorageType<STORE_AS_HANDLE> { |
| 59 typedef Handle<Object> storage_type; |
| 60 }; |
| 61 |
| 62 template <int store_as, int type_of_walk, int where_to_end> |
| 63 class PrototypeIterator; |
| 64 |
| 65 |
| 66 template <int store_as, int where_to_end> |
| 67 class PrototypeIterator<store_as, TYPE_BASED_WALK, where_to_end> { |
| 68 public: |
| 69 typedef typename ObjectStorageType<store_as>::storage_type storage_type; |
| 70 |
| 71 PrototypeIterator(Isolate* isolate, storage_type object) |
| 72 : isolate_(isolate), object_(object) {} |
| 73 ~PrototypeIterator() {} |
| 74 |
| 75 bool IsAtEnd(); |
| 76 PrototypeIterator& Advance(); |
| 77 |
| 78 storage_type GetCurrent() const { return object_; } |
| 79 |
| 80 private: |
| 81 Isolate* isolate_; |
| 82 storage_type object_; |
| 83 |
| 84 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator); |
| 85 }; |
| 86 |
| 87 |
| 88 template <> |
| 89 V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, |
| 90 END_AT_NULL_VALUE>::IsAtEnd() { |
| 91 return object_->IsNull(); |
| 92 } |
| 93 |
| 94 |
| 95 template <> |
| 96 V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, |
| 97 END_AT_NULL_VALUE>::IsAtEnd() { |
| 98 return object_->IsNull(); |
| 99 } |
| 100 |
| 101 |
| 102 template <> |
| 103 V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, |
| 104 END_AT_NON_HIDDEN>::IsAtEnd() { |
| 105 return !object_->IsJSReceiver() || |
| 106 !JSReceiver::cast(object_)->map()->is_hidden_prototype(); |
| 107 } |
| 108 |
| 109 |
| 110 template <> |
| 111 V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, |
| 112 END_AT_NON_HIDDEN>::IsAtEnd() { |
| 113 return !object_->IsJSReceiver() || |
| 114 !Handle<JSReceiver>::cast(object_)->map()->is_hidden_prototype(); |
| 115 } |
| 116 |
| 117 |
| 118 template <> |
| 119 V8_INLINE |
| 120 PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, END_AT_NULL_VALUE>& |
| 121 PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, |
| 122 END_AT_NULL_VALUE>::Advance() { |
| 123 object_ = object_->GetPrototype(isolate_); |
| 124 return *this; |
| 125 } |
| 126 |
| 127 |
| 128 template <> |
| 129 V8_INLINE |
| 130 PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, END_AT_NULL_VALUE>& |
| 131 PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, |
| 132 END_AT_NULL_VALUE>::Advance() { |
| 133 object_ = Object::GetPrototype(isolate_, object_); |
| 134 return *this; |
| 135 } |
| 136 |
| 137 |
| 138 template <> |
| 139 V8_INLINE |
| 140 PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, END_AT_NON_HIDDEN>& |
| 141 PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, |
| 142 END_AT_NON_HIDDEN>::Advance() { |
| 143 object_ = object_->GetPrototype(isolate_); |
| 144 return *this; |
| 145 } |
| 146 |
| 147 |
| 148 template <> |
| 149 V8_INLINE |
| 150 PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, END_AT_NON_HIDDEN>& |
| 151 PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, |
| 152 END_AT_NON_HIDDEN>::Advance() { |
| 153 object_ = Object::GetPrototype(isolate_, object_); |
| 154 return *this; |
| 155 } |
| 156 |
| 157 |
| 158 template <> |
| 159 class PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, END_AT_GIVEN_OBJECT> { |
| 160 public: |
| 161 PrototypeIterator(Isolate* isolate, Handle<Object> object, Handle<Object> end) |
| 162 : isolate_(isolate), object_(object), end_(end) {} |
| 163 ~PrototypeIterator() {} |
| 164 |
| 165 bool IsAtEnd() { return object_->IsNull() || *object_ == *end_; } |
| 166 |
| 167 PrototypeIterator& Advance() { |
| 168 object_ = Object::GetPrototype(isolate_, object_); |
| 169 return *this; |
| 170 } |
| 171 |
| 172 Handle<Object> GetCurrent() const { return object_; } |
| 173 |
| 174 private: |
| 175 Isolate* isolate_; |
| 176 Handle<Object> object_; |
| 177 Handle<Object> end_; |
| 178 |
| 179 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator); |
| 180 }; |
| 181 |
| 182 |
| 183 template <int store_as, int where_to_end> |
| 184 class PrototypeIterator<store_as, MAP_BASED_WALK, where_to_end> { |
| 185 public: |
| 186 typedef typename ObjectStorageType<store_as>::storage_type storage_type; |
| 187 |
| 188 explicit PrototypeIterator(storage_type receiver) : object_(receiver) {} |
| 189 ~PrototypeIterator() {} |
| 190 |
| 191 bool IsAtEnd(); |
| 192 |
| 193 PrototypeIterator& Advance(); |
| 194 |
| 195 storage_type GetCurrent() const { return object_; } |
| 196 |
| 197 private: |
| 198 storage_type object_; |
| 199 |
| 200 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator); |
| 201 }; |
| 202 |
| 203 |
| 204 template <> |
| 205 V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, |
| 206 END_AT_NULL_VALUE>::IsAtEnd() { |
| 207 return object_->IsNull(); |
| 208 } |
| 209 |
| 210 |
| 211 template <> |
| 212 V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, |
| 213 END_AT_NULL_VALUE>::IsAtEnd() { |
| 214 return object_->IsNull(); |
| 215 } |
| 216 |
| 217 |
| 218 template <> |
| 219 V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, |
| 220 END_AT_NON_HIDDEN>::IsAtEnd() { |
| 221 return !object_->IsJSReceiver() || |
| 222 !JSReceiver::cast(object_)->map()->is_hidden_prototype(); |
| 223 } |
| 224 |
| 225 |
| 226 template <> |
| 227 V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, |
| 228 END_AT_NON_HIDDEN>::IsAtEnd() { |
| 229 return !object_->IsJSReceiver() || |
| 230 !Handle<JSReceiver>::cast(object_)->map()->is_hidden_prototype(); |
| 231 } |
| 232 |
| 233 |
| 234 template <> |
| 235 V8_INLINE |
| 236 PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, END_AT_NULL_VALUE>& |
| 237 PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, |
| 238 END_AT_NULL_VALUE>::Advance() { |
| 239 object_ = JSReceiver::cast(object_)->GetPrototype(); |
| 240 return *this; |
| 241 } |
| 242 |
| 243 |
| 244 template <> |
| 245 V8_INLINE PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, END_AT_NULL_VALUE>& |
| 246 PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, |
| 247 END_AT_NULL_VALUE>::Advance() { |
| 248 object_ = handle(Handle<JSReceiver>::cast(object_)->GetPrototype(), |
| 249 Handle<JSReceiver>::cast(object_)->GetIsolate()); |
| 250 return *this; |
| 251 } |
| 252 |
| 253 |
| 254 template <> |
| 255 V8_INLINE |
| 256 PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, END_AT_NON_HIDDEN>& |
| 257 PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, |
| 258 END_AT_NON_HIDDEN>::Advance() { |
| 259 object_ = JSReceiver::cast(object_)->GetPrototype(); |
| 260 return *this; |
| 261 } |
| 262 |
| 263 |
| 264 template <> |
| 265 V8_INLINE PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, END_AT_NON_HIDDEN>& |
| 266 PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, |
| 267 END_AT_NON_HIDDEN>::Advance() { |
| 268 object_ = handle(Handle<JSReceiver>::cast(object_)->GetPrototype(), |
| 269 Handle<JSReceiver>::cast(object_)->GetIsolate()); |
| 270 return *this; |
| 271 } |
| 272 |
| 273 |
| 274 #define SAFE_GET_PROTOTYPE(isolate, object) \ |
| 275 v8::internal::PrototypeIterator< \ |
| 276 v8::internal::STORE_AS_POINTER, v8::internal::TYPE_BASED_WALK, \ |
| 277 v8::internal::END_AT_NULL_VALUE>(isolate, object) \ |
| 278 .Advance() \ |
| 279 .GetCurrent() |
| 280 |
| 281 |
| 282 #define SAFE_GET_PROTOTYPE_FAST(receiver) \ |
| 283 v8::internal::PrototypeIterator<v8::internal::STORE_AS_POINTER, \ |
| 284 v8::internal::MAP_BASED_WALK, \ |
| 285 v8::internal::END_AT_NULL_VALUE>(receiver) \ |
| 286 .Advance() \ |
| 287 .GetCurrent() |
| 288 } |
| 289 } // namespace v8::internal |
| 290 |
| 291 #endif // V8_PROTOTYPE_ITERATOR_H_ |
| OLD | NEW |