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 V8_WARN_UNUSED_RESULT virtual Maybe<bool> SetLength(Handle<JSArray> holder, 70 uint32_t new_length) = 0; 71 72 // Copy all indices that have elements from |object| into the given 73 // KeyAccumulator. For Dictionary-based element-kinds we filter out elements 74 // whose PropertyAttribute match |filter|. 75 V8_WARN_UNUSED_RESULT virtual ExceptionStatus CollectElementIndices( 76 Handle<JSObject> object, Handle<FixedArrayBase> backing_store, 77 KeyAccumulator* keys) = 0; 78 79 V8_WARN_UNUSED_RESULT inline ExceptionStatus CollectElementIndices( 80 Handle<JSObject> object, KeyAccumulator* keys); 81 82 virtual Maybe<bool> CollectValuesOrEntries( 83 Isolate* isolate, Handle<JSObject> object, 84 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, 85 PropertyFilter filter = ALL_PROPERTIES) = 0; 86 87 virtual MaybeHandle<FixedArray> PrependElementIndices( 88 Handle<JSObject> object, Handle<FixedArrayBase> backing_store, 89 Handle<FixedArray> keys, GetKeysConversion convert, 90 PropertyFilter filter = ALL_PROPERTIES) = 0; 91 92 inline MaybeHandle<FixedArray> PrependElementIndices( 93 Handle<JSObject> object, Handle<FixedArray> keys, 94 GetKeysConversion convert, PropertyFilter filter = ALL_PROPERTIES); 95 96 V8_WARN_UNUSED_RESULT virtual ExceptionStatus AddElementsToKeyAccumulator( 97 Handle<JSObject> receiver, KeyAccumulator* accumulator, 98 AddKeyConversion convert) = 0; 99 100 V8_WARN_UNUSED_RESULT virtual Maybe<bool> TransitionElementsKind( 101 Handle<JSObject> object, Handle<Map> map) = 0; 102 V8_WARN_UNUSED_RESULT virtual Maybe<bool> GrowCapacityAndConvert( 103 Handle<JSObject> object, uint32_t capacity) = 0; 104 // Unlike GrowCapacityAndConvert do not attempt to convert the backing store 105 // and simply return false in this case. 106 V8_WARN_UNUSED_RESULT virtual Maybe<bool> GrowCapacity( 107 Handle<JSObject> object, uint32_t index) = 0; 108 109 static void InitializeOncePerProcess(); 110 static void TearDown(); 111 112 virtual void Set(Handle<JSObject> holder, InternalIndex entry, 113 Object value) = 0; 114 115 V8_WARN_UNUSED_RESULT virtual Maybe<bool> Add(Handle<JSObject> object, 116 uint32_t index, 117 Handle<Object> value, 118 PropertyAttributes attributes, 119 uint32_t new_capacity) = 0; 120 121 static Handle<JSArray> Concat(Isolate* isolate, BuiltinArguments* args, 122 uint32_t concat_size, uint32_t result_length); 123 124 V8_WARN_UNUSED_RESULT virtual Maybe<uint32_t> Push(Handle<JSArray> receiver, 125 BuiltinArguments* args, 126 uint32_t push_size) = 0; 127 128 V8_WARN_UNUSED_RESULT virtual Maybe<uint32_t> Unshift( 129 Handle<JSArray> receiver, BuiltinArguments* args, 130 uint32_t unshift_size) = 0; 131 132 V8_WARN_UNUSED_RESULT virtual MaybeHandle<Object> Pop( 133 Handle<JSArray> receiver) = 0; 134 135 V8_WARN_UNUSED_RESULT virtual MaybeHandle<Object> Shift( 136 Handle<JSArray> receiver) = 0; 137 138 virtual Handle<NumberDictionary> Normalize(Handle<JSObject> object) = 0; 139 140 virtual size_t GetCapacity(JSObject holder, FixedArrayBase backing_store) = 0; 141 142 V8_WARN_UNUSED_RESULT virtual MaybeHandle<Object> Fill( 143 Handle<JSObject> receiver, Handle<Object> obj_value, size_t start, 144 size_t end) = 0; 145 146 // Check an Object's own elements for an element (using SameValueZero 147 // semantics) 148 virtual Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver, 149 Handle<Object> value, size_t start, 150 size_t length) = 0; 151 152 // Check an Object's own elements for the index of an element (using SameValue 153 // semantics) 154 virtual Maybe<int64_t> IndexOfValue(Isolate* isolate, 155 Handle<JSObject> receiver, 156 Handle<Object> value, size_t start, 157 size_t length) = 0; 158 159 virtual Maybe<int64_t> LastIndexOfValue(Handle<JSObject> receiver, 160 Handle<Object> value, 161 size_t start) = 0; 162 163 virtual void Reverse(JSObject receiver) = 0; 164 165 virtual void CopyElements(Isolate* isolate, Handle<FixedArrayBase> source, 166 ElementsKind source_kind, 167 Handle<FixedArrayBase> destination, int size) = 0; 168 169 virtual Object CopyElements(Handle<Object> source, 170 Handle<JSObject> destination, size_t length, 171 size_t offset) = 0; 172 173 virtual Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate, 174 Handle<JSObject> object, 175 uint32_t length) = 0; 176 177 virtual void CopyTypedArrayElementsSlice(JSTypedArray source, 178 JSTypedArray destination, 179 size_t start, size_t end) = 0; 180 181 protected: 182 friend class LookupIterator; 183 184 // Element handlers distinguish between entries and indices when they 185 // manipulate elements. Entries refer to elements in terms of their location 186 // in the underlying storage's backing store representation, and are between 0 187 // and GetCapacity. Indices refer to elements in terms of the value that would 188 // be specified in JavaScript to access the element. In most implementations, 189 // indices are equivalent to entries. In the NumberDictionary 190 // ElementsAccessor, entries are mapped to an index using the KeyAt method on 191 // the NumberDictionary. 192 virtual InternalIndex GetEntryForIndex(Isolate* isolate, JSObject holder, 193 FixedArrayBase backing_store, 194 size_t index) = 0; 195 196 virtual PropertyDetails GetDetails(JSObject holder, InternalIndex entry) = 0; 197 virtual void Reconfigure(Handle<JSObject> object, 198 Handle<FixedArrayBase> backing_store, 199 InternalIndex entry, Handle<Object> value, 200 PropertyAttributes attributes) = 0; 201 202 // Deletes an element in an object. 203 virtual void Delete(Handle<JSObject> holder, InternalIndex entry) = 0; 204 205 // NOTE: this method violates the handlified function signature convention: 206 // raw pointer parameter |source_holder| in the function that allocates. 207 // This is done intentionally to avoid ArrayConcat() builtin performance 208 // degradation. 209 virtual void CopyElements(JSObject source_holder, uint32_t source_start, 210 ElementsKind source_kind, 211 Handle<FixedArrayBase> destination, 212 uint32_t destination_start, int copy_size) = 0; 213 214 private: 215 V8_EXPORT_PRIVATE static ElementsAccessor** elements_accessors_; 216 }; 217 218 V8_WARN_UNUSED_RESULT MaybeHandle<Object> ArrayConstructInitializeElements( 219 Handle<JSArray> array, JavaScriptArguments* args); 220 221 // Called directly from CSA. 222 // {raw_context}: Context pointer. 223 // {raw_source}: JSArray pointer. 224 // {raw_destination}: JSTypedArray pointer. 225 void CopyFastNumberJSArrayElementsToTypedArray(Address raw_context, 226 Address raw_source, 227 Address raw_destination, 228 uintptr_t length, 229 uintptr_t offset); 230 // {raw_source}, {raw_destination}: JSTypedArray pointers. 231 void CopyTypedArrayElementsToTypedArray(Address raw_source, 232 Address raw_destination, 233 uintptr_t length, uintptr_t offset); 234 // {raw_source}, {raw_destination}: JSTypedArray pointers. 235 void CopyTypedArrayElementsSlice(Address raw_source, Address raw_destination, 236 uintptr_t start, uintptr_t end); 237 238 } // namespace internal 239 } // namespace v8 240 241 #endif // V8_OBJECTS_ELEMENTS_H_ 242