// 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_FIELD_INDEX_H_
#define V8_FIELD_INDEX_H_

#include "src/property-details.h"
#include "src/utils.h"

namespace v8 {
namespace internal {

class Map;

// Wrapper class to hold a field index, usually but not necessarily generated
// from a property index. When available, the wrapper class captures additional
// information to allow the field index to be translated back into the property
// index it was originally generated from.
class FieldIndex final {
 public:
  enum Encoding { kTagged, kDouble, kWord32 };

  FieldIndex() : bit_field_(0) {}

  static inline FieldIndex ForPropertyIndex(
      const Map map, int index,
      Representation representation = Representation::Tagged());
  static inline FieldIndex ForInObjectOffset(int offset, Encoding encoding);
  static inline FieldIndex ForDescriptor(const Map map, int descriptor_index);

  inline int GetLoadByFieldIndex() const;

  bool is_inobject() const {
    return IsInObjectBits::decode(bit_field_);
  }

  bool is_hidden_field() const { return IsHiddenField::decode(bit_field_); }

  bool is_double() const { return EncodingBits::decode(bit_field_) == kDouble; }

  int offset() const { return OffsetBits::decode(bit_field_); }

  // Zero-indexed from beginning of the object.
  int index() const {
    DCHECK(IsAligned(offset(), kTaggedSize));
    return offset() / kTaggedSize;
  }

  int outobject_array_index() const {
    DCHECK(!is_inobject());
    return index() - first_inobject_property_offset() / kTaggedSize;
  }

  // Zero-based from the first inobject property. Overflows to out-of-object
  // properties.
  int property_index() const {
    DCHECK(!is_hidden_field());
    int result = index() - first_inobject_property_offset() / kTaggedSize;
    if (!is_inobject()) {
      result += InObjectPropertyBits::decode(bit_field_);
    }
    return result;
  }

  int GetFieldAccessStubKey() const {
    return bit_field_ &
           (IsInObjectBits::kMask | EncodingBits::kMask | OffsetBits::kMask);
  }

  bool operator==(FieldIndex const& other) const {
    return bit_field_ == other.bit_field_;
  }
  bool operator!=(FieldIndex const& other) const { return !(*this == other); }

 private:
  FieldIndex(bool is_inobject, int offset, Encoding encoding,
             int inobject_properties, int first_inobject_property_offset,
             bool is_hidden = false) {
    DCHECK(IsAligned(first_inobject_property_offset, kTaggedSize));
    bit_field_ = IsInObjectBits::encode(is_inobject) |
                 EncodingBits::encode(encoding) |
                 FirstInobjectPropertyOffsetBits::encode(
                     first_inobject_property_offset) |
                 IsHiddenField::encode(is_hidden) | OffsetBits::encode(offset) |
                 InObjectPropertyBits::encode(inobject_properties);
  }

  static Encoding FieldEncoding(Representation representation) {
    switch (representation.kind()) {
      case Representation::kNone:
      case Representation::kSmi:
      case Representation::kHeapObject:
      case Representation::kTagged:
        return kTagged;
      case Representation::kDouble:
        return kDouble;
      default:
        break;
    }
    PrintF("%s\n", representation.Mnemonic());
    UNREACHABLE();
    return kTagged;
  }

  int first_inobject_property_offset() const {
    DCHECK(!is_hidden_field());
    return FirstInobjectPropertyOffsetBits::decode(bit_field_);
  }

  static const int kOffsetBitsSize =
      (kDescriptorIndexBitCount + 1 + kTaggedSizeLog2);

  // Index from beginning of object.
  class OffsetBits : public BitField64<int, 0, kOffsetBitsSize> {};
  class IsInObjectBits : public BitField64<bool, OffsetBits::kNext, 1> {};
  class EncodingBits : public BitField64<Encoding, IsInObjectBits::kNext, 2> {};
  // Number of inobject properties.
  class InObjectPropertyBits
      : public BitField64<int, EncodingBits::kNext, kDescriptorIndexBitCount> {
  };
  // Offset of first inobject property from beginning of object.
  class FirstInobjectPropertyOffsetBits
      : public BitField64<int, InObjectPropertyBits::kNext,
                          kFirstInobjectPropertyOffsetBitCount> {};
  class IsHiddenField
      : public BitField64<bool, FirstInobjectPropertyOffsetBits::kNext, 1> {};
  STATIC_ASSERT(IsHiddenField::kNext <= 64);

  uint64_t bit_field_;
};

}  // namespace internal
}  // namespace v8

#endif  // V8_FIELD_INDEX_H_
