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_OBJECTS_ELEMENTS_H_ 6 #define V8_OBJECTS_ELEMENTS_H_ 7 8 #include "src/builtins/builtins-utils.h" 9 #include "src/objects/elements-kind.h" 10 #include "src/objects/internal-index.h" 11 #include "src/objects/keys.h" 12 #include "src/objects/objects.h" 13 14 namespace v8 { 15 namespace internal { 16 17 class JSTypedArray; 18 19 // Abstract base class for handles that can operate on objects with differing 20 // ElementsKinds. 21 class ElementsAccessor { 22 public: 23 ElementsAccessor() = default; 24 virtual ~ElementsAccessor() = default; 25 ElementsAccessor(const ElementsAccessor&) = delete; 26 ElementsAccessor& operator=(const ElementsAccessor&) = delete; 27 28 // Returns a shared ElementsAccessor for the specified ElementsKind. ForKind(ElementsKind elements_kind)29 static ElementsAccessor* ForKind(ElementsKind elements_kind) { 30 DCHECK_LT(static_cast<int>(elements_kind), kElementsKindCount); 31 return elements_accessors_[elements_kind]; 32 } 33 34 // Checks the elements of an object for consistency, asserting when a problem 35 // is found. 36 virtual void Validate(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 first version takes the 40 // backing store to use for the check, which must be compatible with the 41 // ElementsKind of the ElementsAccessor; the second version uses 42 // holder->elements() as the backing store. If a |filter| is specified, 43 // the PropertyAttributes of the element at the given index are compared 44 // to the given |filter|. If they match/overlap, the given index is ignored. 45 // 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(JSObject holder, uint32_t index, 49 FixedArrayBase backing_store, 50 PropertyFilter filter = ALL_PROPERTIES) = 0; 51 52 inline bool HasElement(JSObject holder, uint32_t index, 53 PropertyFilter filter = ALL_PROPERTIES); 54 55 // Note: this is currently not implemented for string wrapper and 56 // typed array elements. 57 virtual bool HasEntry(JSObject holder, InternalIndex entry) = 0; 58 59 virtual Handle<Object> Get(Handle<JSObject> holder, InternalIndex entry) = 0; 60 61 virtual bool HasAccessors(JSObject holder) = 0; 62 virtual size_t NumberOfElements(JSObject holder) = 0; 63 64 // Modifies the length data property as specified for JSArrays and resizes the 65 // underlying backing store accordingly. The method honors the semantics of 66 // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that 67 // have non-deletable elements can only be shrunk to the size of highest 68 // element that is non-deletable. 69 virtual void SetLength(Handle<JSArray> holder, uint32_t new_length) = 0; 70 71 // Copy all indices that have elements from |object| into the given 72 // KeyAccumulator. For Dictionary-based element-kinds we filter out elements 73 // whose PropertyAttribute match |filter|. 74 V8_WARN_UNUSED_RESULT virtual ExceptionStatus CollectElementIndices( 75 Handle<JSObject> object, Handle<FixedArrayBase> backing_store, 76 KeyAccumulator* keys) = 0; 77 78 V8_WARN_UNUSED_RESULT inline ExceptionStatus CollectElementIndices( 79 Handle<JSObject> object, KeyAccumulator* keys); 80 81 virtual Maybe<bool> CollectValuesOrEntries( 82 Isolate* isolate, Handle<JSObject> object, 83 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, 84 PropertyFilter filter = ALL_PROPERTIES) = 0; 85 86 virtual MaybeHandle<FixedArray> PrependElementIndices( 87 Handle<JSObject> object, Handle<FixedArrayBase> backing_store, 88 Handle<FixedArray> keys, GetKeysConversion convert, 89 PropertyFilter filter = ALL_PROPERTIES) = 0; 90 91 inline MaybeHandle<FixedArray> PrependElementIndices( 92 Handle<JSObject> object, Handle<FixedArray> keys, 93 GetKeysConversion convert, PropertyFilter filter = ALL_PROPERTIES); 94 95 V8_WARN_UNUSED_RESULT virtual ExceptionStatus AddElementsToKeyAccumulator( 96 Handle<JSObject> receiver, KeyAccumulator* accumulator, 97 AddKeyConversion convert) = 0; 98 99 virtual void TransitionElementsKind(Handle<JSObject> object, 100 Handle<Map> map) = 0; 101 virtual void GrowCapacityAndConvert(Handle<JSObject> object, 102 uint32_t capacity) = 0; 103 // Unlike GrowCapacityAndConvert do not attempt to convert the backing store 104 // and simply return false in this case. 105 virtual bool GrowCapacity(Handle<JSObject> object, uint32_t index) = 0; 106 107 static void InitializeOncePerProcess(); 108 static void TearDown(); 109 110 virtual void Set(Handle<JSObject> holder, InternalIndex entry, 111 Object value) = 0; 112 113 virtual void Add(Handle<JSObject> object, uint32_t index, 114 Handle<Object> value, PropertyAttributes attributes, 115 uint32_t new_capacity) = 0; 116 117 static Handle<JSArray> Concat(Isolate* isolate, BuiltinArguments* args, 118 uint32_t concat_size, uint32_t result_length); 119 120 virtual uint32_t Push(Handle<JSArray> receiver, BuiltinArguments* args, 121 uint32_t push_size) = 0; 122 123 virtual uint32_t Unshift(Handle<JSArray> receiver, BuiltinArguments* args, 124 uint32_t unshift_size) = 0; 125 126 virtual Handle<Object> Pop(Handle<JSArray> receiver) = 0; 127 128 virtual Handle<Object> Shift(Handle<JSArray> receiver) = 0; 129 130 virtual Handle<NumberDictionary> Normalize(Handle<JSObject> object) = 0; 131 132 virtual size_t GetCapacity(JSObject holder, FixedArrayBase backing_store) = 0; 133 134 virtual Object Fill(Handle<JSObject> receiver, Handle<Object> obj_value, 135 size_t start, size_t end) = 0; 136 137 // Check an Object's own elements for an element (using SameValueZero 138 // semantics) 139 virtual Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver, 140 Handle<Object> value, size_t start, 141 size_t length) = 0; 142 143 // Check an Object's own elements for the index of an element (using SameValue 144 // semantics) 145 virtual Maybe<int64_t> IndexOfValue(Isolate* isolate, 146 Handle<JSObject> receiver, 147 Handle<Object> value, size_t start, 148 size_t length) = 0; 149 150 virtual Maybe<int64_t> LastIndexOfValue(Handle<JSObject> receiver, 151 Handle<Object> value, 152 size_t start) = 0; 153 154 virtual void Reverse(JSObject receiver) = 0; 155 156 virtual void CopyElements(Isolate* isolate, Handle<FixedArrayBase> source, 157 ElementsKind source_kind, 158 Handle<FixedArrayBase> destination, int size) = 0; 159 160 virtual Object CopyElements(Handle<Object> source, 161 Handle<JSObject> destination, size_t length, 162 size_t offset) = 0; 163 164 virtual Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate, 165 Handle<JSObject> object, 166 uint32_t length) = 0; 167 168 virtual void CopyTypedArrayElementsSlice(JSTypedArray source, 169 JSTypedArray destination, 170 size_t start, size_t end) = 0; 171 172 protected: 173 friend class LookupIterator; 174 175 // Element handlers distinguish between entries and indices when they 176 // manipulate elements. Entries refer to elements in terms of their location 177 // in the underlying storage's backing store representation, and are between 0 178 // and GetCapacity. Indices refer to elements in terms of the value that would 179 // be specified in JavaScript to access the element. In most implementations, 180 // indices are equivalent to entries. In the NumberDictionary 181 // ElementsAccessor, entries are mapped to an index using the KeyAt method on 182 // the NumberDictionary. 183 virtual InternalIndex GetEntryForIndex(Isolate* isolate, JSObject holder, 184 FixedArrayBase backing_store, 185 size_t index) = 0; 186 187 virtual PropertyDetails GetDetails(JSObject holder, InternalIndex entry) = 0; 188 virtual void Reconfigure(Handle<JSObject> object, 189 Handle<FixedArrayBase> backing_store, 190 InternalIndex entry, Handle<Object> value, 191 PropertyAttributes attributes) = 0; 192 193 // Deletes an element in an object. 194 virtual void Delete(Handle<JSObject> holder, InternalIndex entry) = 0; 195 196 // NOTE: this method violates the handlified function signature convention: 197 // raw pointer parameter |source_holder| in the function that allocates. 198 // This is done intentionally to avoid ArrayConcat() builtin performance 199 // degradation. 200 virtual void CopyElements(JSObject source_holder, uint32_t source_start, 201 ElementsKind source_kind, 202 Handle<FixedArrayBase> destination, 203 uint32_t destination_start, int copy_size) = 0; 204 205 private: 206 V8_EXPORT_PRIVATE static ElementsAccessor** elements_accessors_; 207 }; 208 209 V8_WARN_UNUSED_RESULT MaybeHandle<Object> ArrayConstructInitializeElements( 210 Handle<JSArray> array, JavaScriptArguments* args); 211 212 // Called directly from CSA. 213 // {raw_context}: Context pointer. 214 // {raw_source}: JSArray pointer. 215 // {raw_destination}: JSTypedArray pointer. 216 void CopyFastNumberJSArrayElementsToTypedArray(Address raw_context, 217 Address raw_source, 218 Address raw_destination, 219 uintptr_t length, 220 uintptr_t offset); 221 // {raw_source}, {raw_destination}: JSTypedArray pointers. 222 void CopyTypedArrayElementsToTypedArray(Address raw_source, 223 Address raw_destination, 224 uintptr_t length, uintptr_t offset); 225 // {raw_source}, {raw_destination}: JSTypedArray pointers. 226 void CopyTypedArrayElementsSlice(Address raw_source, Address raw_destination, 227 uintptr_t start, uintptr_t end); 228 229 } // namespace internal 230 } // namespace v8 231 232 #endif // V8_OBJECTS_ELEMENTS_H_ 233