// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_PROPERTY_H_
#define V8_PROPERTY_H_

#include <iosfwd>

#include "src/factory.h"
#include "src/field-index.h"
#include "src/field-index-inl.h"
#include "src/isolate.h"
#include "src/types.h"

namespace v8 {
namespace internal {

// Abstraction for elements in instance-descriptor arrays.
//
// Each descriptor has a key, property attributes, property type,
// property index (in the actual instance-descriptor array) and
// optionally a piece of data.
class Descriptor BASE_EMBEDDED {
 public:
  void KeyToUniqueName() {
    if (!key_->IsUniqueName()) {
      key_ = key_->GetIsolate()->factory()->InternalizeString(
          Handle<String>::cast(key_));
    }
  }

  Handle<Name> GetKey() const { return key_; }
  Handle<Object> GetValue() const { return value_; }
  PropertyDetails GetDetails() const { return details_; }

  void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }

 private:
  Handle<Name> key_;
  Handle<Object> value_;
  PropertyDetails details_;

 protected:
  Descriptor() : details_(Smi::FromInt(0)) {}

  void Init(Handle<Name> key, Handle<Object> value, PropertyDetails details) {
    key_ = key;
    value_ = value;
    details_ = details;
  }

  Descriptor(Handle<Name> key, Handle<Object> value, PropertyDetails details)
      : key_(key),
        value_(value),
        details_(details) { }

  Descriptor(Handle<Name> key,
             Handle<Object> value,
             PropertyAttributes attributes,
             PropertyType type,
             Representation representation,
             int field_index = 0)
      : key_(key),
        value_(value),
        details_(attributes, type, representation, field_index) { }

  friend class DescriptorArray;
  friend class Map;
};


std::ostream& operator<<(std::ostream& os, const Descriptor& d);


class FieldDescriptor FINAL : public Descriptor {
 public:
  FieldDescriptor(Handle<Name> key,
                  int field_index,
                  PropertyAttributes attributes,
                  Representation representation)
      : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
                   FIELD, representation, field_index) {}
  FieldDescriptor(Handle<Name> key,
                  int field_index,
                  Handle<HeapType> field_type,
                  PropertyAttributes attributes,
                  Representation representation)
      : Descriptor(key, field_type, attributes, FIELD,
                   representation, field_index) { }
};


class ConstantDescriptor FINAL : public Descriptor {
 public:
  ConstantDescriptor(Handle<Name> key,
                     Handle<Object> value,
                     PropertyAttributes attributes)
      : Descriptor(key, value, attributes, CONSTANT,
                   value->OptimalRepresentation()) {}
};


class CallbacksDescriptor FINAL : public Descriptor {
 public:
  CallbacksDescriptor(Handle<Name> key,
                      Handle<Object> foreign,
                      PropertyAttributes attributes)
      : Descriptor(key, foreign, attributes, CALLBACKS,
                   Representation::Tagged()) {}
};


class LookupResult FINAL BASE_EMBEDDED {
 public:
  explicit LookupResult(Isolate* isolate)
      : isolate_(isolate),
        next_(isolate->top_lookup_result()),
        lookup_type_(NOT_FOUND),
        holder_(NULL),
        transition_(NULL),
        details_(NONE, NORMAL, Representation::None()) {
    isolate->set_top_lookup_result(this);
  }

  ~LookupResult() {
    DCHECK(isolate()->top_lookup_result() == this);
    isolate()->set_top_lookup_result(next_);
  }

  Isolate* isolate() const { return isolate_; }

  void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
    lookup_type_ = DESCRIPTOR_TYPE;
    holder_ = holder;
    transition_ = NULL;
    details_ = details;
    number_ = number;
  }

  void TransitionResult(JSObject* holder, Map* target) {
    lookup_type_ = TRANSITION_TYPE;
    number_ = target->LastAdded();
    details_ = target->instance_descriptors()->GetDetails(number_);
    holder_ = holder;
    transition_ = target;
  }

  void NotFound() {
    lookup_type_ = NOT_FOUND;
    details_ = PropertyDetails(NONE, NORMAL, Representation::None());
    holder_ = NULL;
    transition_ = NULL;
  }

  Representation representation() const {
    DCHECK(IsFound());
    return details_.representation();
  }

  // Property callbacks does not include transitions to callbacks.
  bool IsPropertyCallbacks() const {
    DCHECK(!(details_.type() == CALLBACKS && !IsFound()));
    return !IsTransition() && details_.type() == CALLBACKS;
  }

  bool IsReadOnly() const {
    DCHECK(IsFound());
    return details_.IsReadOnly();
  }

  bool IsField() const {
    DCHECK(!(details_.type() == FIELD && !IsFound()));
    return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == FIELD;
  }

  bool IsConstant() const {
    DCHECK(!(details_.type() == CONSTANT && !IsFound()));
    return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == CONSTANT;
  }

  bool IsConfigurable() const { return details_.IsConfigurable(); }
  bool IsFound() const { return lookup_type_ != NOT_FOUND; }
  bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }

  // Is the result is a property excluding transitions and the null descriptor?
  bool IsProperty() const {
    return IsFound() && !IsTransition();
  }

  Map* GetTransitionTarget() const {
    DCHECK(IsTransition());
    return transition_;
  }

  bool IsTransitionToField() const {
    return IsTransition() && details_.type() == FIELD;
  }

  int GetLocalFieldIndexFromMap(Map* map) const {
    return GetFieldIndexFromMap(map) - map->inobject_properties();
  }

  Object* GetConstantFromMap(Map* map) const {
    DCHECK(details_.type() == CONSTANT);
    return GetValueFromMap(map);
  }

  Object* GetValueFromMap(Map* map) const {
    DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
           lookup_type_ == TRANSITION_TYPE);
    DCHECK(number_ < map->NumberOfOwnDescriptors());
    return map->instance_descriptors()->GetValue(number_);
  }

  int GetFieldIndexFromMap(Map* map) const {
    DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
           lookup_type_ == TRANSITION_TYPE);
    DCHECK(number_ < map->NumberOfOwnDescriptors());
    return map->instance_descriptors()->GetFieldIndex(number_);
  }

  HeapType* GetFieldTypeFromMap(Map* map) const {
    DCHECK_NE(NOT_FOUND, lookup_type_);
    DCHECK(number_ < map->NumberOfOwnDescriptors());
    return map->instance_descriptors()->GetFieldType(number_);
  }

  Map* GetFieldOwnerFromMap(Map* map) const {
    DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
           lookup_type_ == TRANSITION_TYPE);
    DCHECK(number_ < map->NumberOfOwnDescriptors());
    return map->FindFieldOwner(number_);
  }

  void Iterate(ObjectVisitor* visitor);

 private:
  Isolate* isolate_;
  LookupResult* next_;

  // Where did we find the result;
  enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_;

  JSReceiver* holder_;
  Map* transition_;
  int number_;
  PropertyDetails details_;
};


std::ostream& operator<<(std::ostream& os, const LookupResult& r);
} }  // namespace v8::internal

#endif  // V8_PROPERTY_H_
