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