blob: 4df1114c7705780ef2a97ae677b734857c9dbf90 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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_