19bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org// Copyright 2014 the V8 project authors. All rights reserved.
29bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org// Use of this source code is governed by a BSD-style license that can be
39bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org// found in the LICENSE file.
49bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
59bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org#ifndef V8_PROTOTYPE_H_
69bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org#define V8_PROTOTYPE_H_
79bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
89bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org#include "src/isolate.h"
99bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org#include "src/objects.h"
109bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
119bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.orgnamespace v8 {
129bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.orgnamespace internal {
139bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
149bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org/**
159bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * A class to uniformly access the prototype of any Object and walk its
169bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * prototype chain.
179bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org *
189bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * The PrototypeIterator can either start at the prototype (default), or
199bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * include the receiver itself. If a PrototypeIterator is constructed for a
209bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * Map, it will always start at the prototype.
219bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org *
229bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * The PrototypeIterator can either run to the null_value(), the first
239bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org * non-hidden prototype, or a given object.
249bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org */
259bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.orgclass PrototypeIterator {
269bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org public:
279bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  enum WhereToStart { START_AT_RECEIVER, START_AT_PROTOTYPE };
289bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
299bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
309bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
319bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  PrototypeIterator(Isolate* isolate, Handle<Object> receiver,
329bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org                    WhereToStart where_to_start = START_AT_PROTOTYPE)
339bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      : did_jump_to_prototype_chain_(false),
349bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        object_(NULL),
359bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        handle_(receiver),
369bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        isolate_(isolate) {
379bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    CHECK(!handle_.is_null());
389bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    if (where_to_start == START_AT_PROTOTYPE) {
399bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      Advance();
409bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    }
419bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
429bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  PrototypeIterator(Isolate* isolate, Object* receiver,
439bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org                    WhereToStart where_to_start = START_AT_PROTOTYPE)
449bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      : did_jump_to_prototype_chain_(false),
459bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        object_(receiver),
469bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        isolate_(isolate) {
479bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    if (where_to_start == START_AT_PROTOTYPE) {
489bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      Advance();
499bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    }
509bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
519bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  explicit PrototypeIterator(Map* receiver_map)
529bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      : did_jump_to_prototype_chain_(true),
539bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        object_(receiver_map->prototype()),
549bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        isolate_(receiver_map->GetIsolate()) {}
5593720aaa16a789ba13d52a265a479b26f4885e2emachenbach@chromium.org  explicit PrototypeIterator(Handle<Map> receiver_map)
5693720aaa16a789ba13d52a265a479b26f4885e2emachenbach@chromium.org      : did_jump_to_prototype_chain_(true),
5793720aaa16a789ba13d52a265a479b26f4885e2emachenbach@chromium.org        object_(NULL),
5893720aaa16a789ba13d52a265a479b26f4885e2emachenbach@chromium.org        handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())),
5993720aaa16a789ba13d52a265a479b26f4885e2emachenbach@chromium.org        isolate_(receiver_map->GetIsolate()) {}
609bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  ~PrototypeIterator() {}
619bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
629bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  Object* GetCurrent() const {
63e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(handle_.is_null());
649bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    return object_;
659bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
669bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  static Handle<Object> GetCurrent(const PrototypeIterator& iterator) {
67e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(!iterator.handle_.is_null());
689bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    return iterator.handle_;
699bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
709bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  void Advance() {
719bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    if (handle_.is_null() && object_->IsJSProxy()) {
729bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      did_jump_to_prototype_chain_ = true;
739bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      object_ = isolate_->heap()->null_value();
749bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      return;
759bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    } else if (!handle_.is_null() && handle_->IsJSProxy()) {
769bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      did_jump_to_prototype_chain_ = true;
779bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      handle_ = handle(isolate_->heap()->null_value(), isolate_);
789bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      return;
799bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    }
809bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    AdvanceIgnoringProxies();
819bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
829bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  void AdvanceIgnoringProxies() {
839bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    if (!did_jump_to_prototype_chain_) {
849bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      did_jump_to_prototype_chain_ = true;
859bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      if (handle_.is_null()) {
869bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        object_ = object_->GetRootMap(isolate_)->prototype();
879bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      } else {
889bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        handle_ = handle(handle_->GetRootMap(isolate_)->prototype(), isolate_);
899bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      }
909bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    } else {
919bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      if (handle_.is_null()) {
929bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        object_ = HeapObject::cast(object_)->map()->prototype();
939bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      } else {
949bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org        handle_ =
959bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org            handle(HeapObject::cast(*handle_)->map()->prototype(), isolate_);
969bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      }
979bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    }
989bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
999bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  bool IsAtEnd(WhereToEnd where_to_end = END_AT_NULL) const {
1009bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    if (handle_.is_null()) {
1019bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      return object_->IsNull() ||
1029bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org             (did_jump_to_prototype_chain_ &&
1039bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org              where_to_end == END_AT_NON_HIDDEN &&
1049bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org              !HeapObject::cast(object_)->map()->is_hidden_prototype());
1059bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    } else {
1069bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org      return handle_->IsNull() ||
1079bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org             (did_jump_to_prototype_chain_ &&
1089bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org              where_to_end == END_AT_NON_HIDDEN &&
1099bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org              !Handle<HeapObject>::cast(handle_)->map()->is_hidden_prototype());
1109bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    }
1119bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
1129bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  bool IsAtEnd(Object* final_object) {
113e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(handle_.is_null());
1149bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    return object_->IsNull() || object_ == final_object;
1159bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
1169bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  bool IsAtEnd(Handle<Object> final_object) {
117e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(!handle_.is_null());
1189bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org    return handle_->IsNull() || *handle_ == *final_object;
1199bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  }
1209bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
1219bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org private:
1229bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  bool did_jump_to_prototype_chain_;
1239bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  Object* object_;
1249bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  Handle<Object> handle_;
1259bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  Isolate* isolate_;
1269bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
1279bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org  DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
1289bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org};
1299bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
1309bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
1319bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org}  // namespace internal
1329bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
1339bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org}  // namespace v8
1349bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org
1359bf7aff6cc5ed8807b7b2abc11b6cf77b928ded1machenbach@chromium.org#endif  // V8_PROTOTYPE_H_
136