1// Copyright 2012 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_ELEMENTS_H_
6#define V8_ELEMENTS_H_
7
8#include "src/elements-kind.h"
9#include "src/heap/heap.h"
10#include "src/isolate.h"
11#include "src/key-accumulator.h"
12#include "src/objects.h"
13
14namespace v8 {
15namespace internal {
16
17// Abstract base class for handles that can operate on objects with differing
18// ElementsKinds.
19class ElementsAccessor {
20 public:
21  explicit ElementsAccessor(const char* name) : name_(name) { }
22  virtual ~ElementsAccessor() { }
23
24  const char* name() const { return name_; }
25
26  // Returns a shared ElementsAccessor for the specified ElementsKind.
27  static ElementsAccessor* ForKind(ElementsKind elements_kind) {
28    DCHECK(static_cast<int>(elements_kind) < kElementsKindCount);
29    return elements_accessors_[elements_kind];
30  }
31
32  static ElementsAccessor* ForArray(Handle<FixedArrayBase> array);
33
34  // Checks the elements of an object for consistency, asserting when a problem
35  // is found.
36  virtual void Validate(Handle<JSObject> obj) = 0;
37
38  // Returns true if a holder contains an element with the specified index
39  // without iterating up the prototype chain.  The caller can optionally pass
40  // in the backing store to use for the check, which must be compatible with
41  // the ElementsKind of the ElementsAccessor. If backing_store is NULL, the
42  // holder->elements() is used as the backing store. If a |filter| is
43  // specified the PropertyAttributes of the element at the given index
44  // are compared to the given |filter|. If they match/overlap the given
45  // index is ignored. Note that only Dictionary elements have custom
46  // PropertyAttributes associated, hence the |filter| argument is ignored for
47  // all but DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
48  virtual bool HasElement(Handle<JSObject> holder, uint32_t index,
49                          Handle<FixedArrayBase> backing_store,
50                          PropertyFilter filter = ALL_PROPERTIES) = 0;
51
52  inline bool HasElement(Handle<JSObject> holder, uint32_t index,
53                         PropertyFilter filter = ALL_PROPERTIES) {
54    return HasElement(holder, index, handle(holder->elements()), filter);
55  }
56
57  // Returns true if the backing store is compact in the given range
58  virtual bool IsPacked(Handle<JSObject> holder,
59                        Handle<FixedArrayBase> backing_store, uint32_t start,
60                        uint32_t end) = 0;
61
62  virtual Handle<Object> Get(Handle<FixedArrayBase> backing_store,
63                             uint32_t entry) = 0;
64
65  // Modifies the length data property as specified for JSArrays and resizes the
66  // underlying backing store accordingly. The method honors the semantics of
67  // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that
68  // have non-deletable elements can only be shrunk to the size of highest
69  // element that is non-deletable.
70  virtual void SetLength(Handle<JSArray> holder, uint32_t new_length) = 0;
71
72  // Deletes an element in an object.
73  virtual void Delete(Handle<JSObject> holder, uint32_t entry) = 0;
74
75  // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all
76  // of elements from source after source_start to the destination array.
77  static const int kCopyToEnd = -1;
78  // If kCopyToEndAndInitializeToHole is specified as the copy_size to
79  // CopyElements, it copies all of elements from source after source_start to
80  // destination array, padding any remaining uninitialized elements in the
81  // destination array with the hole.
82  static const int kCopyToEndAndInitializeToHole = -2;
83
84  // Copy elements from one backing store to another. Typically, callers specify
85  // the source JSObject or JSArray in source_holder. If the holder's backing
86  // store is available, it can be passed in source and source_holder is
87  // ignored.
88  virtual void CopyElements(
89      Handle<FixedArrayBase> source,
90      uint32_t source_start,
91      ElementsKind source_kind,
92      Handle<FixedArrayBase> destination,
93      uint32_t destination_start,
94      int copy_size) = 0;
95
96  // NOTE: this method violates the handlified function signature convention:
97  // raw pointer parameter |source_holder| in the function that allocates.
98  // This is done intentionally to avoid ArrayConcat() builtin performance
99  // degradation.
100  virtual void CopyElements(
101      JSObject* source_holder,
102      uint32_t source_start,
103      ElementsKind source_kind,
104      Handle<FixedArrayBase> destination,
105      uint32_t destination_start,
106      int copy_size) = 0;
107
108  inline void CopyElements(
109      Handle<JSObject> from_holder,
110      Handle<FixedArrayBase> to,
111      ElementsKind from_kind) {
112    CopyElements(
113      *from_holder, 0, from_kind, to, 0, kCopyToEndAndInitializeToHole);
114  }
115
116  // Copy all indices that have elements from |object| into the given
117  // KeyAccumulator. For Dictionary-based element-kinds we filter out elements
118  // whose PropertyAttribute match |filter|.
119  virtual void CollectElementIndices(Handle<JSObject> object,
120                                     Handle<FixedArrayBase> backing_store,
121                                     KeyAccumulator* keys,
122                                     uint32_t range = kMaxUInt32,
123                                     PropertyFilter filter = ALL_PROPERTIES,
124                                     uint32_t offset = 0) = 0;
125
126  inline void CollectElementIndices(Handle<JSObject> object,
127                                    KeyAccumulator* keys,
128                                    uint32_t range = kMaxUInt32,
129                                    PropertyFilter filter = ALL_PROPERTIES,
130                                    uint32_t offset = 0) {
131    CollectElementIndices(object, handle(object->elements()), keys, range,
132                          filter, offset);
133  }
134
135  virtual void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
136                                           KeyAccumulator* accumulator,
137                                           AddKeyConversion convert) = 0;
138
139  virtual void GrowCapacityAndConvert(Handle<JSObject> object,
140                                      uint32_t capacity) = 0;
141
142  static void InitializeOncePerProcess();
143  static void TearDown();
144
145  virtual void Set(FixedArrayBase* backing_store, uint32_t entry,
146                   Object* value) = 0;
147
148  virtual void Reconfigure(Handle<JSObject> object,
149                           Handle<FixedArrayBase> backing_store, uint32_t entry,
150                           Handle<Object> value,
151                           PropertyAttributes attributes) = 0;
152
153  virtual void Add(Handle<JSObject> object, uint32_t index,
154                   Handle<Object> value, PropertyAttributes attributes,
155                   uint32_t new_capacity) = 0;
156
157  static Handle<JSArray> Concat(Isolate* isolate, Arguments* args,
158                                uint32_t concat_size);
159
160  virtual uint32_t Push(Handle<JSArray> receiver,
161                        Handle<FixedArrayBase> backing_store, Arguments* args,
162                        uint32_t push_size) = 0;
163
164  virtual uint32_t Unshift(Handle<JSArray> receiver,
165                           Handle<FixedArrayBase> backing_store,
166                           Arguments* args, uint32_t unshift_size) = 0;
167
168  virtual Handle<JSArray> Slice(Handle<JSObject> receiver,
169                                Handle<FixedArrayBase> backing_store,
170                                uint32_t start, uint32_t end) = 0;
171
172  virtual Handle<JSArray> Splice(Handle<JSArray> receiver,
173                                 Handle<FixedArrayBase> backing_store,
174                                 uint32_t start, uint32_t delete_count,
175                                 Arguments* args, uint32_t add_count) = 0;
176
177  virtual Handle<Object> Pop(Handle<JSArray> receiver,
178                             Handle<FixedArrayBase> backing_store) = 0;
179
180  virtual Handle<Object> Shift(Handle<JSArray> receiver,
181                               Handle<FixedArrayBase> backing_store) = 0;
182
183 protected:
184  friend class LookupIterator;
185
186  static ElementsAccessor* ForArray(FixedArrayBase* array);
187
188
189  // Element handlers distinguish between entries and indices when they
190  // manipulate elements. Entries refer to elements in terms of their location
191  // in the underlying storage's backing store representation, and are between 0
192  // and GetCapacity. Indices refer to elements in terms of the value that would
193  // be specified in JavaScript to access the element. In most implementations,
194  // indices are equivalent to entries. In the NumberDictionary
195  // ElementsAccessor, entries are mapped to an index using the KeyAt method on
196  // the NumberDictionary.
197  virtual uint32_t GetEntryForIndex(JSObject* holder,
198                                    FixedArrayBase* backing_store,
199                                    uint32_t index) = 0;
200  virtual PropertyDetails GetDetails(FixedArrayBase* backing_store,
201                                     uint32_t entry) = 0;
202
203 private:
204  virtual uint32_t GetCapacity(JSObject* holder,
205                               FixedArrayBase* backing_store) = 0;
206  static ElementsAccessor** elements_accessors_;
207  const char* name_;
208
209  DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
210};
211
212void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
213                     bool allow_appending = false);
214
215MUST_USE_RESULT MaybeHandle<Object> ArrayConstructInitializeElements(
216    Handle<JSArray> array,
217    Arguments* args);
218
219}  // namespace internal
220}  // namespace v8
221
222#endif  // V8_ELEMENTS_H_
223