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
11namespace v8 {
12namespace 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 */
25class 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)
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)
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  }
51  explicit PrototypeIterator(Map* receiver_map)
52      : did_jump_to_prototype_chain_(true),
53        object_(receiver_map->prototype()),
54        isolate_(receiver_map->GetIsolate()) {}
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()) {}
60  ~PrototypeIterator() {}
61
62  Object* GetCurrent() const {
63    DCHECK(handle_.is_null());
64    return object_;
65  }
66  static Handle<Object> GetCurrent(const PrototypeIterator& iterator) {
67    DCHECK(!iterator.handle_.is_null());
68    return iterator.handle_;
69  }
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  }
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  }
112  bool IsAtEnd(Object* final_object) {
113    DCHECK(handle_.is_null());
114    return object_->IsNull() || object_ == final_object;
115  }
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