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