Home | History | Annotate | Download | only in src
      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)
     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