elements.h 9.43 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_ELEMENTS_H_
#define V8_ELEMENTS_H_

8
#include "elements-kind.h"
9
#include "objects.h"
10 11
#include "heap.h"
#include "isolate.h"
12 13 14 15 16 17 18 19

namespace v8 {
namespace internal {

// Abstract base class for handles that can operate on objects with differing
// ElementsKinds.
class ElementsAccessor {
 public:
20
  explicit ElementsAccessor(const char* name) : name_(name) { }
21
  virtual ~ElementsAccessor() { }
22

23 24
  virtual ElementsKind kind() const = 0;
  const char* name() const { return name_; }
25

26 27
  // Checks the elements of an object for consistency, asserting when a problem
  // is found.
28
  virtual void Validate(Handle<JSObject> obj) = 0;
29

30 31 32 33 34
  // Returns true if a holder contains an element with the specified key
  // without iterating up the prototype chain.  The caller can optionally pass
  // in the backing store to use for the check, which must be compatible with
  // the ElementsKind of the ElementsAccessor. If backing_store is NULL, the
  // holder->elements() is used as the backing store.
35 36 37 38 39 40 41 42 43 44 45 46
  virtual bool HasElement(
      Handle<Object> receiver,
      Handle<JSObject> holder,
      uint32_t key,
      Handle<FixedArrayBase> backing_store) = 0;

  inline bool HasElement(
      Handle<Object> receiver,
      Handle<JSObject> holder,
      uint32_t key) {
    return HasElement(receiver, holder, key, handle(holder->elements()));
  }
47 48 49 50 51 52

  // Returns the element with the specified key or undefined if there is no such
  // element. This method doesn't iterate up the prototype chain.  The caller
  // can optionally pass in the backing store to use for the check, which must
  // be compatible with the ElementsKind of the ElementsAccessor. If
  // backing_store is NULL, the holder->elements() is used as the backing store.
53
  MUST_USE_RESULT virtual MaybeHandle<Object> Get(
54 55 56
      Handle<Object> receiver,
      Handle<JSObject> holder,
      uint32_t key,
57 58
      Handle<FixedArrayBase> backing_store) = 0;

59
  MUST_USE_RESULT inline MaybeHandle<Object> Get(
60 61
      Handle<Object> receiver,
      Handle<JSObject> holder,
62 63 64
      uint32_t key) {
    return Get(receiver, holder, key, handle(holder->elements()));
  }
65

66 67 68 69 70 71
  // Returns an element's attributes, or ABSENT if there is no such
  // element. This method doesn't iterate up the prototype chain.  The caller
  // can optionally pass in the backing store to use for the check, which must
  // be compatible with the ElementsKind of the ElementsAccessor. If
  // backing_store is NULL, the holder->elements() is used as the backing store.
  MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
72 73
      Handle<Object> receiver,
      Handle<JSObject> holder,
74
      uint32_t key,
75 76 77 78 79 80 81 82
      Handle<FixedArrayBase> backing_store) = 0;

  MUST_USE_RESULT inline PropertyAttributes GetAttributes(
      Handle<Object> receiver,
      Handle<JSObject> holder,
      uint32_t key) {
    return GetAttributes(receiver, holder, key, handle(holder->elements()));
  }
83

84 85 86 87 88 89
  // Returns an element's type, or NONEXISTENT if there is no such
  // element. This method doesn't iterate up the prototype chain.  The caller
  // can optionally pass in the backing store to use for the check, which must
  // be compatible with the ElementsKind of the ElementsAccessor. If
  // backing_store is NULL, the holder->elements() is used as the backing store.
  MUST_USE_RESULT virtual PropertyType GetType(
90 91
      Handle<Object> receiver,
      Handle<JSObject> holder,
92
      uint32_t key,
93 94 95 96 97 98 99 100
      Handle<FixedArrayBase> backing_store) = 0;

  MUST_USE_RESULT inline PropertyType GetType(
      Handle<Object> receiver,
      Handle<JSObject> holder,
      uint32_t key) {
    return GetType(receiver, holder, key, handle(holder->elements()));
  }
101 102 103 104 105 106

  // Returns an element's accessors, or NULL if the element does not exist or
  // is plain. This method doesn't iterate up the prototype chain.  The caller
  // can optionally pass in the backing store to use for the check, which must
  // be compatible with the ElementsKind of the ElementsAccessor. If
  // backing_store is NULL, the holder->elements() is used as the backing store.
107 108 109
  MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
      Handle<Object> receiver,
      Handle<JSObject> holder,
110
      uint32_t key,
111 112 113 114 115 116 117 118
      Handle<FixedArrayBase> backing_store) = 0;

  MUST_USE_RESULT inline MaybeHandle<AccessorPair> GetAccessorPair(
      Handle<Object> receiver,
      Handle<JSObject> holder,
      uint32_t key) {
    return GetAccessorPair(receiver, holder, key, handle(holder->elements()));
  }
119

120 121 122 123 124
  // Modifies the length data property as specified for JSArrays and resizes the
  // underlying backing store accordingly. The method honors the semantics of
  // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that
  // have non-deletable elements can only be shrunk to the size of highest
  // element that is non-deletable.
125
  MUST_USE_RESULT virtual MaybeHandle<Object> SetLength(
126 127
      Handle<JSArray> holder,
      Handle<Object> new_length) = 0;
128

129 130 131 132 133 134
  // Modifies both the length and capacity of a JSArray, resizing the underlying
  // backing store as necessary. This method does NOT honor the semantics of
  // EcmaScript 5.1 15.4.5.2, arrays can be shrunk beyond non-deletable
  // elements. This method should only be called for array expansion OR by
  // runtime JavaScript code that use InternalArrays and don't care about
  // EcmaScript 5.1 semantics.
135 136 137 138
  virtual void SetCapacityAndLength(
      Handle<JSArray> array,
      int capacity,
      int length) = 0;
139

140
  // Deletes an element in an object, returning a new elements backing store.
141
  MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
142 143 144
      Handle<JSObject> holder,
      uint32_t key,
      JSReceiver::DeleteMode mode) = 0;
145

146 147 148 149 150 151 152 153 154
  // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all
  // of elements from source after source_start to the destination array.
  static const int kCopyToEnd = -1;
  // If kCopyToEndAndInitializeToHole is specified as the copy_size to
  // CopyElements, it copies all of elements from source after source_start to
  // destination array, padding any remaining uninitialized elements in the
  // destination array with the hole.
  static const int kCopyToEndAndInitializeToHole = -2;

155 156 157 158
  // Copy elements from one backing store to another. Typically, callers specify
  // the source JSObject or JSArray in source_holder. If the holder's backing
  // store is available, it can be passed in source and source_holder is
  // ignored.
159
  virtual void CopyElements(
160 161 162 163 164 165 166 167 168 169 170 171
      Handle<FixedArrayBase> source,
      uint32_t source_start,
      ElementsKind source_kind,
      Handle<FixedArrayBase> destination,
      uint32_t destination_start,
      int copy_size) = 0;

  // TODO(ishell): Keeping |source_holder| parameter in a non-handlified form
  // helps avoiding ArrayConcat() builtin performance degradation.
  // Revisit this later.
  virtual void CopyElements(
      JSObject* source_holder,
172 173 174 175
      uint32_t source_start,
      ElementsKind source_kind,
      Handle<FixedArrayBase> destination,
      uint32_t destination_start,
176
      int copy_size) = 0;
177

178
  inline void CopyElements(
179 180
      Handle<JSObject> from_holder,
      Handle<FixedArrayBase> to,
181 182 183
      ElementsKind from_kind) {
    CopyElements(
      *from_holder, 0, from_kind, to, 0, kCopyToEndAndInitializeToHole);
184 185
  }

186
  MUST_USE_RESULT virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
187 188 189 190 191
      Handle<Object> receiver,
      Handle<JSObject> holder,
      Handle<FixedArray> to,
      Handle<FixedArrayBase> from) = 0;

192
  MUST_USE_RESULT inline MaybeHandle<FixedArray> AddElementsToFixedArray(
193 194 195 196 197 198
      Handle<Object> receiver,
      Handle<JSObject> holder,
      Handle<FixedArray> to) {
    return AddElementsToFixedArray(
        receiver, holder, to, handle(holder->elements()));
  }
199

200
  // Returns a shared ElementsAccessor for the specified ElementsKind.
201 202
  static ElementsAccessor* ForKind(ElementsKind elements_kind) {
    ASSERT(elements_kind < kElementsKindCount);
203 204 205
    return elements_accessors_[elements_kind];
  }

206
  static ElementsAccessor* ForArray(Handle<FixedArrayBase> array);
207

208
  static void InitializeOncePerProcess();
209
  static void TearDown();
210

211
 protected:
212
  friend class SloppyArgumentsElementsAccessor;
213

214
  virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) = 0;
215

216
  // Element handlers distinguish between indexes and keys when they manipulate
217
  // elements.  Indexes refer to elements in terms of their location in the
218
  // underlying storage's backing store representation, and are between 0 and
219
  // GetCapacity.  Keys refer to elements in terms of the value that would be
220 221 222 223
  // specified in JavaScript to access the element. In most implementations,
  // keys are equivalent to indexes, and GetKeyForIndex returns the same value
  // it is passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps
  // the index to a key using the KeyAt method on the NumberDictionary.
224
  virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store,
225 226
                                  uint32_t index) = 0;

227 228
 private:
  static ElementsAccessor** elements_accessors_;
229
  const char* name_;
230 231 232 233

  DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
};

234
void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key,
235
                     bool allow_appending = false);
236

237 238 239
MUST_USE_RESULT MaybeHandle<Object> ArrayConstructInitializeElements(
    Handle<JSArray> array,
    Arguments* args);
240

241 242 243
} }  // namespace v8::internal

#endif  // V8_ELEMENTS_H_