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.
8 #include "src/elements-kind.h"
9 #include "src/heap/heap.h"
10 #include "src/isolate.h"
11 #include "src/objects.h"
16 // Abstract base class for handles that can operate on objects with differing
18 class ElementsAccessor {
20 explicit ElementsAccessor(const char* name) : name_(name) { }
21 virtual ~ElementsAccessor() { }
23 virtual ElementsKind kind() const = 0;
24 const char* name() const { return name_; }
26 // Checks the elements of an object for consistency, asserting when a problem
28 virtual void Validate(Handle<JSObject> obj) = 0;
30 // Returns true if a holder contains an element with the specified key
31 // without iterating up the prototype chain. The caller can optionally pass
32 // in the backing store to use for the check, which must be compatible with
33 // the ElementsKind of the ElementsAccessor. If backing_store is NULL, the
34 // holder->elements() is used as the backing store.
35 virtual bool HasElement(
36 Handle<Object> receiver,
37 Handle<JSObject> holder,
39 Handle<FixedArrayBase> backing_store) = 0;
41 inline bool HasElement(
42 Handle<Object> receiver,
43 Handle<JSObject> holder,
45 return HasElement(receiver, holder, key, handle(holder->elements()));
48 // Returns the element with the specified key or undefined if there is no such
49 // element. This method doesn't iterate up the prototype chain. The caller
50 // can optionally pass in the backing store to use for the check, which must
51 // be compatible with the ElementsKind of the ElementsAccessor. If
52 // backing_store is NULL, the holder->elements() is used as the backing store.
53 MUST_USE_RESULT virtual MaybeHandle<Object> Get(
54 Handle<Object> receiver,
55 Handle<JSObject> holder,
57 Handle<FixedArrayBase> backing_store) = 0;
59 MUST_USE_RESULT inline MaybeHandle<Object> Get(
60 Handle<Object> receiver,
61 Handle<JSObject> holder,
63 return Get(receiver, holder, key, handle(holder->elements()));
66 // Returns an element's attributes, or ABSENT if there is no such
67 // element. This method doesn't iterate up the prototype chain. The caller
68 // can optionally pass in the backing store to use for the check, which must
69 // be compatible with the ElementsKind of the ElementsAccessor. If
70 // backing_store is NULL, the holder->elements() is used as the backing store.
71 MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
72 Handle<Object> receiver,
73 Handle<JSObject> holder,
75 Handle<FixedArrayBase> backing_store) = 0;
77 MUST_USE_RESULT inline PropertyAttributes GetAttributes(
78 Handle<Object> receiver,
79 Handle<JSObject> holder,
81 return GetAttributes(receiver, holder, key, handle(holder->elements()));
84 // Returns an element's accessors, or NULL if the element does not exist or
85 // is plain. This method doesn't iterate up the prototype chain. The caller
86 // can optionally pass in the backing store to use for the check, which must
87 // be compatible with the ElementsKind of the ElementsAccessor. If
88 // backing_store is NULL, the holder->elements() is used as the backing store.
89 MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
90 Handle<Object> receiver,
91 Handle<JSObject> holder,
93 Handle<FixedArrayBase> backing_store) = 0;
95 MUST_USE_RESULT inline MaybeHandle<AccessorPair> GetAccessorPair(
96 Handle<Object> receiver,
97 Handle<JSObject> holder,
99 return GetAccessorPair(receiver, holder, key, handle(holder->elements()));
102 // Modifies the length data property as specified for JSArrays and resizes the
103 // underlying backing store accordingly. The method honors the semantics of
104 // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that
105 // have non-deletable elements can only be shrunk to the size of highest
106 // element that is non-deletable.
107 MUST_USE_RESULT virtual MaybeHandle<Object> SetLength(
108 Handle<JSArray> holder,
109 Handle<Object> new_length) = 0;
111 // Modifies both the length and capacity of a JSArray, resizing the underlying
112 // backing store as necessary. This method does NOT honor the semantics of
113 // EcmaScript 5.1 15.4.5.2, arrays can be shrunk beyond non-deletable
114 // elements. This method should only be called for array expansion OR by
115 // runtime JavaScript code that use InternalArrays and don't care about
116 // EcmaScript 5.1 semantics.
117 virtual void SetCapacityAndLength(
118 Handle<JSArray> array,
122 // Deletes an element in an object, returning a new elements backing store.
123 MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
124 Handle<JSObject> holder,
126 JSReceiver::DeleteMode mode) = 0;
128 // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all
129 // of elements from source after source_start to the destination array.
130 static const int kCopyToEnd = -1;
131 // If kCopyToEndAndInitializeToHole is specified as the copy_size to
132 // CopyElements, it copies all of elements from source after source_start to
133 // destination array, padding any remaining uninitialized elements in the
134 // destination array with the hole.
135 static const int kCopyToEndAndInitializeToHole = -2;
137 // Copy elements from one backing store to another. Typically, callers specify
138 // the source JSObject or JSArray in source_holder. If the holder's backing
139 // store is available, it can be passed in source and source_holder is
141 virtual void CopyElements(
142 Handle<FixedArrayBase> source,
143 uint32_t source_start,
144 ElementsKind source_kind,
145 Handle<FixedArrayBase> destination,
146 uint32_t destination_start,
149 // TODO(ishell): Keeping |source_holder| parameter in a non-handlified form
150 // helps avoiding ArrayConcat() builtin performance degradation.
151 // Revisit this later.
152 virtual void CopyElements(
153 JSObject* source_holder,
154 uint32_t source_start,
155 ElementsKind source_kind,
156 Handle<FixedArrayBase> destination,
157 uint32_t destination_start,
160 inline void CopyElements(
161 Handle<JSObject> from_holder,
162 Handle<FixedArrayBase> to,
163 ElementsKind from_kind) {
165 *from_holder, 0, from_kind, to, 0, kCopyToEndAndInitializeToHole);
168 MUST_USE_RESULT virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
169 Handle<Object> receiver,
170 Handle<JSObject> holder,
171 Handle<FixedArray> to,
172 Handle<FixedArrayBase> from) = 0;
174 MUST_USE_RESULT inline MaybeHandle<FixedArray> AddElementsToFixedArray(
175 Handle<Object> receiver,
176 Handle<JSObject> holder,
177 Handle<FixedArray> to) {
178 return AddElementsToFixedArray(
179 receiver, holder, to, handle(holder->elements()));
182 // Returns a shared ElementsAccessor for the specified ElementsKind.
183 static ElementsAccessor* ForKind(ElementsKind elements_kind) {
184 DCHECK(static_cast<int>(elements_kind) < kElementsKindCount);
185 return elements_accessors_[elements_kind];
188 static ElementsAccessor* ForArray(Handle<FixedArrayBase> array);
190 static void InitializeOncePerProcess();
191 static void TearDown();
194 friend class SloppyArgumentsElementsAccessor;
196 virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) = 0;
198 // Element handlers distinguish between indexes and keys when they manipulate
199 // elements. Indexes refer to elements in terms of their location in the
200 // underlying storage's backing store representation, and are between 0 and
201 // GetCapacity. Keys refer to elements in terms of the value that would be
202 // specified in JavaScript to access the element. In most implementations,
203 // keys are equivalent to indexes, and GetKeyForIndex returns the same value
204 // it is passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps
205 // the index to a key using the KeyAt method on the NumberDictionary.
206 virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store,
210 static ElementsAccessor** elements_accessors_;
213 DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
216 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key,
217 bool allow_appending = false);
219 MUST_USE_RESULT MaybeHandle<Object> ArrayConstructInitializeElements(
220 Handle<JSArray> array,
223 } } // namespace v8::internal
225 #endif // V8_ELEMENTS_H_