// 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 "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 {

class OStream;

// 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;
};


OStream& operator<<(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_;
};


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

#endif  // V8_PROPERTY_H_
