// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_OBJECTS_JS_ARRAY_H_ #define V8_OBJECTS_JS_ARRAY_H_ #include "src/objects.h" #include "src/objects/fixed-array.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8 { namespace internal { // The JSArray describes JavaScript Arrays // Such an array can be in one of two modes: // - fast, backing storage is a FixedArray and length <= elements.length(); // Please note: push and pop can be used to grow and shrink the array. // - slow, backing storage is a HashTable with numbers as keys. class JSArray : public JSObject { public: // [length]: The length property. DECL_ACCESSORS(length, Object) // Overload the length setter to skip write barrier when the length // is set to a smi. This matches the set function on FixedArray. inline void set_length(Smi* length); static bool HasReadOnlyLength(Handle array); static bool WouldChangeReadOnlyLength(Handle array, uint32_t index); // Initialize the array with the given capacity. The function may // fail due to out-of-memory situations, but only if the requested // capacity is non-zero. static void Initialize(Handle array, int capacity, int length = 0); // If the JSArray has fast elements, and new_length would result in // normalization, returns true. bool SetLengthWouldNormalize(uint32_t new_length); static inline bool SetLengthWouldNormalize(Heap* heap, uint32_t new_length); // Initializes the array to a certain length. inline bool AllowsSetLength(); static void SetLength(Handle array, uint32_t length); // Set the content of the array to the content of storage. static inline void SetContent(Handle array, Handle storage); // ES6 9.4.2.1 V8_WARN_UNUSED_RESULT static Maybe DefineOwnProperty( Isolate* isolate, Handle o, Handle name, PropertyDescriptor* desc, ShouldThrow should_throw); static bool AnythingToArrayLength(Isolate* isolate, Handle length_object, uint32_t* output); V8_WARN_UNUSED_RESULT static Maybe ArraySetLength( Isolate* isolate, Handle a, PropertyDescriptor* desc, ShouldThrow should_throw); // Checks whether the Array has the current realm's Array.prototype as its // prototype. This function is best-effort and only gives a conservative // approximation, erring on the side of false, in particular with respect // to Proxies and objects with a hidden prototype. inline bool HasArrayPrototype(Isolate* isolate); DECL_CAST(JSArray) // Dispatched behavior. DECL_PRINTER(JSArray) DECL_VERIFIER(JSArray) // Number of element slots to pre-allocate for an empty array. static const int kPreallocatedArrayElements = 4; // Layout description. static const int kLengthOffset = JSObject::kHeaderSize; static const int kSize = kLengthOffset + kPointerSize; static const int kLengthDescriptorIndex = 0; // Max. number of elements being copied in Array builtins. static const int kMaxCopyElements = 100; // This constant is somewhat arbitrary. Any large enough value would work. static const uint32_t kMaxFastArrayLength = 32 * 1024 * 1024; static const int kInitialMaxFastElementArray = (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - kSize - AllocationMemento::kSize) >> kDoubleSizeLog2; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSArray); }; Handle CacheInitialJSArrayMaps(Handle native_context, Handle initial_map); // The JSArrayIterator describes JavaScript Array Iterators Objects, as // defined in ES section #sec-array-iterator-objects. class JSArrayIterator : public JSObject { public: DECL_PRINTER(JSArrayIterator) DECL_VERIFIER(JSArrayIterator) DECL_CAST(JSArrayIterator) // [iterated_object]: the [[IteratedObject]] inobject property. DECL_ACCESSORS(iterated_object, Object) // [next_index]: The [[ArrayIteratorNextIndex]] inobject property. DECL_ACCESSORS(next_index, Object) // [kind]: the [[ArrayIterationKind]] inobject property. inline IterationKind kind() const; inline void set_kind(IterationKind kind); static const int kIteratedObjectOffset = JSObject::kHeaderSize; static const int kNextIndexOffset = kIteratedObjectOffset + kPointerSize; static const int kKindOffset = kNextIndexOffset + kPointerSize; static const int kSize = kKindOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayIterator); }; // Whether a JSArrayBuffer is a SharedArrayBuffer or not. enum class SharedFlag { kNotShared, kShared }; class JSArrayBuffer : public JSObject { public: // [byte_length]: length in bytes DECL_ACCESSORS(byte_length, Object) // [backing_store]: backing memory for this array DECL_ACCESSORS(backing_store, void) // For non-wasm, allocation_length and allocation_base are byte_length and // backing_store, respectively. inline size_t allocation_length() const; inline void* allocation_base() const; inline uint32_t bit_field() const; inline void set_bit_field(uint32_t bits); // [is_external]: true indicates that the embedder is in charge of freeing the // backing_store, while is_external == false means that v8 will free the // memory block once all ArrayBuffers referencing it are collected by the GC. inline bool is_external(); inline void set_is_external(bool value); inline bool is_neuterable(); inline void set_is_neuterable(bool value); inline bool was_neutered(); inline void set_was_neutered(bool value); inline bool is_shared(); inline void set_is_shared(bool value); inline bool is_growable(); inline void set_is_growable(bool value); DECL_CAST(JSArrayBuffer) void Neuter(); inline ArrayBuffer::Allocator::AllocationMode allocation_mode() const; struct Allocation { using AllocationMode = ArrayBuffer::Allocator::AllocationMode; Allocation(void* allocation_base, size_t length, void* backing_store, AllocationMode mode, bool is_wasm_memory) : allocation_base(allocation_base), length(length), backing_store(backing_store), mode(mode), is_wasm_memory(is_wasm_memory) {} void* allocation_base; size_t length; void* backing_store; AllocationMode mode; bool is_wasm_memory; }; // Returns whether the buffer is tracked by the WasmMemoryTracker. inline bool is_wasm_memory() const; // Sets whether the buffer is tracked by the WasmMemoryTracker. void set_is_wasm_memory(bool is_wasm_memory); void FreeBackingStoreFromMainThread(); static void FreeBackingStore(Isolate* isolate, Allocation allocation); V8_EXPORT_PRIVATE static void Setup( Handle array_buffer, Isolate* isolate, bool is_external, void* data, size_t allocated_length, SharedFlag shared = SharedFlag::kNotShared, bool is_wasm_memory = false); // Returns false if array buffer contents could not be allocated. // In this case, |array_buffer| will not be set up. static bool SetupAllocatingData( Handle array_buffer, Isolate* isolate, size_t allocated_length, bool initialize = true, SharedFlag shared = SharedFlag::kNotShared) V8_WARN_UNUSED_RESULT; // Dispatched behavior. DECL_PRINTER(JSArrayBuffer) DECL_VERIFIER(JSArrayBuffer) static const int kByteLengthOffset = JSObject::kHeaderSize; // The rest of the fields are not JSObjects, so they are not iterated over in // objects-body-descriptors-inl.h. static const int kBackingStoreOffset = kByteLengthOffset + kPointerSize; static const int kBitFieldSlot = kBackingStoreOffset + kPointerSize; #if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT static const int kBitFieldOffset = kBitFieldSlot; #else static const int kBitFieldOffset = kBitFieldSlot + kInt32Size; #endif static const int kSize = kBitFieldSlot + kPointerSize; static const int kSizeWithEmbedderFields = kSize + v8::ArrayBuffer::kEmbedderFieldCount * kPointerSize; // Iterates all fields in the object including internal ones except // kBackingStoreOffset and kBitFieldSlot. class BodyDescriptor; // No weak fields. typedef BodyDescriptor BodyDescriptorWeak; class IsExternal : public BitField {}; class IsNeuterable : public BitField {}; class WasNeutered : public BitField {}; class IsShared : public BitField {}; class IsGrowable : public BitField {}; class IsWasmMemory : public BitField {}; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer); }; class JSArrayBufferView : public JSObject { public: // [buffer]: ArrayBuffer that this typed array views. DECL_ACCESSORS(buffer, Object) // [byte_offset]: offset of typed array in bytes. DECL_ACCESSORS(byte_offset, Object) // [byte_length]: length of typed array in bytes. DECL_ACCESSORS(byte_length, Object) DECL_CAST(JSArrayBufferView) DECL_VERIFIER(JSArrayBufferView) inline bool WasNeutered() const; static const int kBufferOffset = JSObject::kHeaderSize; static const int kByteOffsetOffset = kBufferOffset + kPointerSize; static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize; static const int kViewSize = kByteLengthOffset + kPointerSize; private: #ifdef VERIFY_HEAP DECL_ACCESSORS(raw_byte_offset, Object) DECL_ACCESSORS(raw_byte_length, Object) #endif DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBufferView); }; class JSTypedArray : public JSArrayBufferView { public: // [length]: length of typed array in elements. DECL_ACCESSORS(length, Object) inline uint32_t length_value() const; // ES6 9.4.5.3 V8_WARN_UNUSED_RESULT static Maybe DefineOwnProperty( Isolate* isolate, Handle o, Handle key, PropertyDescriptor* desc, ShouldThrow should_throw); DECL_CAST(JSTypedArray) ExternalArrayType type(); V8_EXPORT_PRIVATE size_t element_size(); Handle GetBuffer(); // Whether the buffer's backing store is on-heap or off-heap. inline bool is_on_heap() const; static inline MaybeHandle Validate(Isolate* isolate, Handle receiver, const char* method_name); // Dispatched behavior. DECL_PRINTER(JSTypedArray) DECL_VERIFIER(JSTypedArray) static const int kLengthOffset = kViewSize; static const int kSize = kLengthOffset + kPointerSize; static const int kSizeWithEmbedderFields = kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize; private: static Handle MaterializeArrayBuffer( Handle typed_array); #ifdef VERIFY_HEAP DECL_ACCESSORS(raw_length, Object) #endif DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray); }; class JSDataView : public JSArrayBufferView { public: DECL_CAST(JSDataView) // Dispatched behavior. DECL_PRINTER(JSDataView) DECL_VERIFIER(JSDataView) static const int kSize = kViewSize; static const int kSizeWithEmbedderFields = kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataView); }; } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" #endif // V8_OBJECTS_JS_ARRAY_H_