1 // Copyright 2017 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_JS_ARRAY_H_ 6 #define V8_OBJECTS_JS_ARRAY_H_ 7 8 #include "src/objects.h" 9 #include "src/objects/fixed-array.h" 10 11 // Has to be the last include (doesn't have include guards): 12 #include "src/objects/object-macros.h" 13 14 namespace v8 { 15 namespace internal { 16 17 // The JSArray describes JavaScript Arrays 18 // Such an array can be in one of two modes: 19 // - fast, backing storage is a FixedArray and length <= elements.length(); 20 // Please note: push and pop can be used to grow and shrink the array. 21 // - slow, backing storage is a HashTable with numbers as keys. 22 class JSArray : public JSObject { 23 public: 24 // [length]: The length property. 25 DECL_ACCESSORS(length, Object) 26 27 // Overload the length setter to skip write barrier when the length 28 // is set to a smi. This matches the set function on FixedArray. 29 inline void set_length(Smi* length); 30 31 static bool HasReadOnlyLength(Handle<JSArray> array); 32 static bool WouldChangeReadOnlyLength(Handle<JSArray> array, uint32_t index); 33 34 // Initialize the array with the given capacity. The function may 35 // fail due to out-of-memory situations, but only if the requested 36 // capacity is non-zero. 37 static void Initialize(Handle<JSArray> array, int capacity, int length = 0); 38 39 // If the JSArray has fast elements, and new_length would result in 40 // normalization, returns true. 41 bool SetLengthWouldNormalize(uint32_t new_length); 42 static inline bool SetLengthWouldNormalize(Heap* heap, uint32_t new_length); 43 44 // Initializes the array to a certain length. 45 inline bool AllowsSetLength(); 46 47 static void SetLength(Handle<JSArray> array, uint32_t length); 48 49 // Set the content of the array to the content of storage. 50 static inline void SetContent(Handle<JSArray> array, 51 Handle<FixedArrayBase> storage); 52 53 // ES6 9.4.2.1 54 V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty( 55 Isolate* isolate, Handle<JSArray> o, Handle<Object> name, 56 PropertyDescriptor* desc, ShouldThrow should_throw); 57 58 static bool AnythingToArrayLength(Isolate* isolate, 59 Handle<Object> length_object, 60 uint32_t* output); 61 V8_WARN_UNUSED_RESULT static Maybe<bool> ArraySetLength( 62 Isolate* isolate, Handle<JSArray> a, PropertyDescriptor* desc, 63 ShouldThrow should_throw); 64 65 // Checks whether the Array has the current realm's Array.prototype as its 66 // prototype. This function is best-effort and only gives a conservative 67 // approximation, erring on the side of false, in particular with respect 68 // to Proxies and objects with a hidden prototype. 69 inline bool HasArrayPrototype(Isolate* isolate); 70 71 DECL_CAST(JSArray) 72 73 // Dispatched behavior. 74 DECL_PRINTER(JSArray) 75 DECL_VERIFIER(JSArray) 76 77 // Number of element slots to pre-allocate for an empty array. 78 static const int kPreallocatedArrayElements = 4; 79 80 // Layout description. 81 static const int kLengthOffset = JSObject::kHeaderSize; 82 static const int kSize = kLengthOffset + kPointerSize; 83 84 static const int kLengthDescriptorIndex = 0; 85 86 // Max. number of elements being copied in Array builtins. 87 static const int kMaxCopyElements = 100; 88 89 // This constant is somewhat arbitrary. Any large enough value would work. 90 static const uint32_t kMaxFastArrayLength = 32 * 1024 * 1024; 91 92 static const int kInitialMaxFastElementArray = 93 (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - kSize - 94 AllocationMemento::kSize) >> 95 kDoubleSizeLog2; 96 97 private: 98 DISALLOW_IMPLICIT_CONSTRUCTORS(JSArray); 99 }; 100 101 Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context, 102 Handle<Map> initial_map); 103 104 // The JSArrayIterator describes JavaScript Array Iterators Objects, as 105 // defined in ES section #sec-array-iterator-objects. 106 class JSArrayIterator : public JSObject { 107 public: 108 DECL_PRINTER(JSArrayIterator) 109 DECL_VERIFIER(JSArrayIterator) 110 111 DECL_CAST(JSArrayIterator) 112 113 // [iterated_object]: the [[IteratedObject]] inobject property. 114 DECL_ACCESSORS(iterated_object, Object) 115 116 // [next_index]: The [[ArrayIteratorNextIndex]] inobject property. 117 DECL_ACCESSORS(next_index, Object) 118 119 // [kind]: the [[ArrayIterationKind]] inobject property. 120 inline IterationKind kind() const; 121 inline void set_kind(IterationKind kind); 122 123 static const int kIteratedObjectOffset = JSObject::kHeaderSize; 124 static const int kNextIndexOffset = kIteratedObjectOffset + kPointerSize; 125 static const int kKindOffset = kNextIndexOffset + kPointerSize; 126 static const int kSize = kKindOffset + kPointerSize; 127 128 private: 129 DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayIterator); 130 }; 131 132 // Whether a JSArrayBuffer is a SharedArrayBuffer or not. 133 enum class SharedFlag { kNotShared, kShared }; 134 135 class JSArrayBuffer : public JSObject { 136 public: 137 // [byte_length]: length in bytes 138 DECL_ACCESSORS(byte_length, Object) 139 140 // [backing_store]: backing memory for this array 141 DECL_ACCESSORS(backing_store, void) 142 143 // For non-wasm, allocation_length and allocation_base are byte_length and 144 // backing_store, respectively. 145 inline size_t allocation_length() const; 146 inline void* allocation_base() const; 147 148 inline uint32_t bit_field() const; 149 inline void set_bit_field(uint32_t bits); 150 151 // [is_external]: true indicates that the embedder is in charge of freeing the 152 // backing_store, while is_external == false means that v8 will free the 153 // memory block once all ArrayBuffers referencing it are collected by the GC. 154 inline bool is_external(); 155 inline void set_is_external(bool value); 156 157 inline bool is_neuterable(); 158 inline void set_is_neuterable(bool value); 159 160 inline bool was_neutered(); 161 inline void set_was_neutered(bool value); 162 163 inline bool is_shared(); 164 inline void set_is_shared(bool value); 165 166 inline bool is_growable(); 167 inline void set_is_growable(bool value); 168 169 DECL_CAST(JSArrayBuffer) 170 171 void Neuter(); 172 173 inline ArrayBuffer::Allocator::AllocationMode allocation_mode() const; 174 175 struct Allocation { 176 using AllocationMode = ArrayBuffer::Allocator::AllocationMode; 177 AllocationAllocation178 Allocation(void* allocation_base, size_t length, void* backing_store, 179 AllocationMode mode, bool is_wasm_memory) 180 : allocation_base(allocation_base), 181 length(length), 182 backing_store(backing_store), 183 mode(mode), 184 is_wasm_memory(is_wasm_memory) {} 185 186 void* allocation_base; 187 size_t length; 188 void* backing_store; 189 AllocationMode mode; 190 bool is_wasm_memory; 191 }; 192 193 // Returns whether the buffer is tracked by the WasmMemoryTracker. 194 inline bool is_wasm_memory() const; 195 196 // Sets whether the buffer is tracked by the WasmMemoryTracker. 197 void set_is_wasm_memory(bool is_wasm_memory); 198 199 void FreeBackingStoreFromMainThread(); 200 static void FreeBackingStore(Isolate* isolate, Allocation allocation); 201 202 V8_EXPORT_PRIVATE static void Setup( 203 Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external, 204 void* data, size_t allocated_length, 205 SharedFlag shared = SharedFlag::kNotShared, bool is_wasm_memory = false); 206 207 // Returns false if array buffer contents could not be allocated. 208 // In this case, |array_buffer| will not be set up. 209 static bool SetupAllocatingData( 210 Handle<JSArrayBuffer> array_buffer, Isolate* isolate, 211 size_t allocated_length, bool initialize = true, 212 SharedFlag shared = SharedFlag::kNotShared) V8_WARN_UNUSED_RESULT; 213 214 // Dispatched behavior. 215 DECL_PRINTER(JSArrayBuffer) 216 DECL_VERIFIER(JSArrayBuffer) 217 218 static const int kByteLengthOffset = JSObject::kHeaderSize; 219 // The rest of the fields are not JSObjects, so they are not iterated over in 220 // objects-body-descriptors-inl.h. 221 static const int kBackingStoreOffset = kByteLengthOffset + kPointerSize; 222 static const int kBitFieldSlot = kBackingStoreOffset + kPointerSize; 223 #if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT 224 static const int kBitFieldOffset = kBitFieldSlot; 225 #else 226 static const int kBitFieldOffset = kBitFieldSlot + kInt32Size; 227 #endif 228 static const int kSize = kBitFieldSlot + kPointerSize; 229 230 static const int kSizeWithEmbedderFields = 231 kSize + v8::ArrayBuffer::kEmbedderFieldCount * kPointerSize; 232 233 // Iterates all fields in the object including internal ones except 234 // kBackingStoreOffset and kBitFieldSlot. 235 class BodyDescriptor; 236 // No weak fields. 237 typedef BodyDescriptor BodyDescriptorWeak; 238 239 class IsExternal : public BitField<bool, 1, 1> {}; 240 class IsNeuterable : public BitField<bool, 2, 1> {}; 241 class WasNeutered : public BitField<bool, 3, 1> {}; 242 class IsShared : public BitField<bool, 4, 1> {}; 243 class IsGrowable : public BitField<bool, 5, 1> {}; 244 class IsWasmMemory : public BitField<bool, 6, 1> {}; 245 246 private: 247 DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer); 248 }; 249 250 class JSArrayBufferView : public JSObject { 251 public: 252 // [buffer]: ArrayBuffer that this typed array views. 253 DECL_ACCESSORS(buffer, Object) 254 255 // [byte_offset]: offset of typed array in bytes. 256 DECL_ACCESSORS(byte_offset, Object) 257 258 // [byte_length]: length of typed array in bytes. 259 DECL_ACCESSORS(byte_length, Object) 260 261 DECL_CAST(JSArrayBufferView) 262 263 DECL_VERIFIER(JSArrayBufferView) 264 265 inline bool WasNeutered() const; 266 267 static const int kBufferOffset = JSObject::kHeaderSize; 268 static const int kByteOffsetOffset = kBufferOffset + kPointerSize; 269 static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize; 270 static const int kViewSize = kByteLengthOffset + kPointerSize; 271 272 private: 273 #ifdef VERIFY_HEAP 274 DECL_ACCESSORS(raw_byte_offset, Object) 275 DECL_ACCESSORS(raw_byte_length, Object) 276 #endif 277 278 DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBufferView); 279 }; 280 281 class JSTypedArray : public JSArrayBufferView { 282 public: 283 // [length]: length of typed array in elements. 284 DECL_ACCESSORS(length, Object) 285 inline uint32_t length_value() const; 286 287 // ES6 9.4.5.3 288 V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty( 289 Isolate* isolate, Handle<JSTypedArray> o, Handle<Object> key, 290 PropertyDescriptor* desc, ShouldThrow should_throw); 291 292 DECL_CAST(JSTypedArray) 293 294 ExternalArrayType type(); 295 V8_EXPORT_PRIVATE size_t element_size(); 296 297 Handle<JSArrayBuffer> GetBuffer(); 298 299 // Whether the buffer's backing store is on-heap or off-heap. 300 inline bool is_on_heap() const; 301 302 static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate, 303 Handle<Object> receiver, 304 const char* method_name); 305 306 // Dispatched behavior. 307 DECL_PRINTER(JSTypedArray) 308 DECL_VERIFIER(JSTypedArray) 309 310 static const int kLengthOffset = kViewSize; 311 static const int kSize = kLengthOffset + kPointerSize; 312 313 static const int kSizeWithEmbedderFields = 314 kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize; 315 316 private: 317 static Handle<JSArrayBuffer> MaterializeArrayBuffer( 318 Handle<JSTypedArray> typed_array); 319 #ifdef VERIFY_HEAP 320 DECL_ACCESSORS(raw_length, Object) 321 #endif 322 323 DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray); 324 }; 325 326 class JSDataView : public JSArrayBufferView { 327 public: 328 DECL_CAST(JSDataView) 329 330 // Dispatched behavior. 331 DECL_PRINTER(JSDataView) 332 DECL_VERIFIER(JSDataView) 333 334 static const int kSize = kViewSize; 335 336 static const int kSizeWithEmbedderFields = 337 kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize; 338 339 private: 340 DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataView); 341 }; 342 343 } // namespace internal 344 } // namespace v8 345 346 #include "src/objects/object-macros-undef.h" 347 348 #endif // V8_OBJECTS_JS_ARRAY_H_ 349