• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 namespace v8 {
15 namespace internal {
16 
17 // Abstract base class for handles that can operate on objects with differing
18 // ElementsKinds.
19 class ElementsAccessor {
20  public:
ElementsAccessor(const char * name)21   explicit ElementsAccessor(const char* name) : name_(name) { }
~ElementsAccessor()22   virtual ~ElementsAccessor() { }
23 
name()24   const char* name() const { return name_; }
25 
26   // Returns a shared ElementsAccessor for the specified ElementsKind.
ForKind(ElementsKind elements_kind)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 
CopyElements(Handle<JSObject> from_holder,Handle<FixedArrayBase> to,ElementsKind from_kind)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 
212 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
213                      bool allow_appending = false);
214 
215 MUST_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