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_OBJECTS_FIELD_INDEX_H_
6#define V8_OBJECTS_FIELD_INDEX_H_
7
8// TODO(jkummerow): Consider forward-declaring instead.
9#include "src/objects/internal-index.h"
10#include "src/objects/property-details.h"
11#include "src/utils/utils.h"
12
13namespace v8 {
14namespace internal {
15
16class Map;
17
18// Wrapper class to hold a field index, usually but not necessarily generated
19// from a property index. When available, the wrapper class captures additional
20// information to allow the field index to be translated back into the property
21// index it was originally generated from.
22class FieldIndex final {
23 public:
24  enum Encoding { kTagged, kDouble, kWord32 };
25
26  FieldIndex() : bit_field_(0) {}
27
28  static inline FieldIndex ForPropertyIndex(
29      Map map, int index,
30      Representation representation = Representation::Tagged());
31  static inline FieldIndex ForInObjectOffset(int offset, Encoding encoding);
32  static inline FieldIndex ForDescriptor(Map map,
33                                         InternalIndex descriptor_index);
34  static inline FieldIndex ForDescriptor(PtrComprCageBase cage_base, Map map,
35                                         InternalIndex descriptor_index);
36
37  inline int GetLoadByFieldIndex() const;
38
39  bool is_inobject() const { return IsInObjectBits::decode(bit_field_); }
40
41  bool is_double() const { return EncodingBits::decode(bit_field_) == kDouble; }
42
43  int offset() const { return OffsetBits::decode(bit_field_); }
44
45  uint64_t bit_field() const { return bit_field_; }
46
47  // Zero-indexed from beginning of the object.
48  int index() const {
49    DCHECK(IsAligned(offset(), kTaggedSize));
50    return offset() / kTaggedSize;
51  }
52
53  int outobject_array_index() const {
54    DCHECK(!is_inobject());
55    return index() - first_inobject_property_offset() / kTaggedSize;
56  }
57
58  // Zero-based from the first inobject property. Overflows to out-of-object
59  // properties.
60  int property_index() const {
61    int result = index() - first_inobject_property_offset() / kTaggedSize;
62    if (!is_inobject()) {
63      result += InObjectPropertyBits::decode(bit_field_);
64    }
65    return result;
66  }
67
68  int GetFieldAccessStubKey() const {
69    return bit_field_ &
70           (IsInObjectBits::kMask | EncodingBits::kMask | OffsetBits::kMask);
71  }
72
73  bool operator==(FieldIndex const& other) const {
74    return bit_field_ == other.bit_field_;
75  }
76  bool operator!=(FieldIndex const& other) const { return !(*this == other); }
77
78 private:
79  FieldIndex(bool is_inobject, int offset, Encoding encoding,
80             int inobject_properties, int first_inobject_property_offset) {
81    DCHECK(IsAligned(first_inobject_property_offset, kTaggedSize));
82    bit_field_ = IsInObjectBits::encode(is_inobject) |
83                 EncodingBits::encode(encoding) |
84                 FirstInobjectPropertyOffsetBits::encode(
85                     first_inobject_property_offset) |
86                 OffsetBits::encode(offset) |
87                 InObjectPropertyBits::encode(inobject_properties);
88  }
89
90  static Encoding FieldEncoding(Representation representation) {
91    switch (representation.kind()) {
92      case Representation::kNone:
93      case Representation::kSmi:
94      case Representation::kHeapObject:
95      case Representation::kTagged:
96        return kTagged;
97      case Representation::kDouble:
98        return kDouble;
99      default:
100        break;
101    }
102    PrintF("%s\n", representation.Mnemonic());
103    UNREACHABLE();
104    return kTagged;
105  }
106
107  int first_inobject_property_offset() const {
108    return FirstInobjectPropertyOffsetBits::decode(bit_field_);
109  }
110
111  static const int kOffsetBitsSize =
112      (kDescriptorIndexBitCount + 1 + kTaggedSizeLog2);
113
114  // Index from beginning of object.
115  using OffsetBits = base::BitField64<int, 0, kOffsetBitsSize>;
116  using IsInObjectBits = OffsetBits::Next<bool, 1>;
117  using EncodingBits = IsInObjectBits::Next<Encoding, 2>;
118  // Number of inobject properties.
119  using InObjectPropertyBits =
120      EncodingBits::Next<int, kDescriptorIndexBitCount>;
121  // Offset of first inobject property from beginning of object.
122  using FirstInobjectPropertyOffsetBits =
123      InObjectPropertyBits::Next<int, kFirstInobjectPropertyOffsetBitCount>;
124  STATIC_ASSERT(FirstInobjectPropertyOffsetBits::kLastUsedBit < 64);
125
126  uint64_t bit_field_;
127};
128
129}  // namespace internal
130}  // namespace v8
131
132#endif  // V8_OBJECTS_FIELD_INDEX_H_
133