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_H_ 6 #define V8_PROTOTYPE_H_ 7 8 #include "src/isolate.h" 9 #include "src/objects.h" 10 11 namespace v8 { 12 namespace 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 */ 25 class PrototypeIterator { 26 public: 27 enum WhereToStart { START_AT_RECEIVER, START_AT_PROTOTYPE }; 28 29 enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN }; 30 31 PrototypeIterator(Isolate* isolate, Handle<Object> receiver, 32 WhereToStart where_to_start = START_AT_PROTOTYPE) did_jump_to_prototype_chain_(false)33 : did_jump_to_prototype_chain_(false), 34 object_(NULL), 35 handle_(receiver), 36 isolate_(isolate) { 37 CHECK(!handle_.is_null()); 38 if (where_to_start == START_AT_PROTOTYPE) { 39 Advance(); 40 } 41 } 42 PrototypeIterator(Isolate* isolate, Object* receiver, 43 WhereToStart where_to_start = START_AT_PROTOTYPE) did_jump_to_prototype_chain_(false)44 : did_jump_to_prototype_chain_(false), 45 object_(receiver), 46 isolate_(isolate) { 47 if (where_to_start == START_AT_PROTOTYPE) { 48 Advance(); 49 } 50 } PrototypeIterator(Map * receiver_map)51 explicit PrototypeIterator(Map* receiver_map) 52 : did_jump_to_prototype_chain_(true), 53 object_(receiver_map->prototype()), 54 isolate_(receiver_map->GetIsolate()) {} PrototypeIterator(Handle<Map> receiver_map)55 explicit PrototypeIterator(Handle<Map> receiver_map) 56 : did_jump_to_prototype_chain_(true), 57 object_(NULL), 58 handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())), 59 isolate_(receiver_map->GetIsolate()) {} ~PrototypeIterator()60 ~PrototypeIterator() {} 61 GetCurrent()62 Object* GetCurrent() const { 63 DCHECK(handle_.is_null()); 64 return object_; 65 } GetCurrent(const PrototypeIterator & iterator)66 static Handle<Object> GetCurrent(const PrototypeIterator& iterator) { 67 DCHECK(!iterator.handle_.is_null()); 68 return iterator.handle_; 69 } Advance()70 void Advance() { 71 if (handle_.is_null() && object_->IsJSProxy()) { 72 did_jump_to_prototype_chain_ = true; 73 object_ = isolate_->heap()->null_value(); 74 return; 75 } else if (!handle_.is_null() && handle_->IsJSProxy()) { 76 did_jump_to_prototype_chain_ = true; 77 handle_ = handle(isolate_->heap()->null_value(), isolate_); 78 return; 79 } 80 AdvanceIgnoringProxies(); 81 } AdvanceIgnoringProxies()82 void AdvanceIgnoringProxies() { 83 if (!did_jump_to_prototype_chain_) { 84 did_jump_to_prototype_chain_ = true; 85 if (handle_.is_null()) { 86 object_ = object_->GetRootMap(isolate_)->prototype(); 87 } else { 88 handle_ = handle(handle_->GetRootMap(isolate_)->prototype(), isolate_); 89 } 90 } else { 91 if (handle_.is_null()) { 92 object_ = HeapObject::cast(object_)->map()->prototype(); 93 } else { 94 handle_ = 95 handle(HeapObject::cast(*handle_)->map()->prototype(), isolate_); 96 } 97 } 98 } 99 bool IsAtEnd(WhereToEnd where_to_end = END_AT_NULL) const { 100 if (handle_.is_null()) { 101 return object_->IsNull() || 102 (did_jump_to_prototype_chain_ && 103 where_to_end == END_AT_NON_HIDDEN && 104 !HeapObject::cast(object_)->map()->is_hidden_prototype()); 105 } else { 106 return handle_->IsNull() || 107 (did_jump_to_prototype_chain_ && 108 where_to_end == END_AT_NON_HIDDEN && 109 !Handle<HeapObject>::cast(handle_)->map()->is_hidden_prototype()); 110 } 111 } IsAtEnd(Object * final_object)112 bool IsAtEnd(Object* final_object) { 113 DCHECK(handle_.is_null()); 114 return object_->IsNull() || object_ == final_object; 115 } IsAtEnd(Handle<Object> final_object)116 bool IsAtEnd(Handle<Object> final_object) { 117 DCHECK(!handle_.is_null()); 118 return handle_->IsNull() || *handle_ == *final_object; 119 } 120 121 private: 122 bool did_jump_to_prototype_chain_; 123 Object* object_; 124 Handle<Object> handle_; 125 Isolate* isolate_; 126 127 DISALLOW_COPY_AND_ASSIGN(PrototypeIterator); 128 }; 129 130 131 } // namespace internal 132 133 } // namespace v8 134 135 #endif // V8_PROTOTYPE_H_ 136