• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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