Home | History | Annotate | Download | only in src
      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:
     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 
    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