blob: 806c275c8f7175ba151eba4a2832853053bb0030 [file] [log] [blame]
// 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<JSArray> array);
static bool WouldChangeReadOnlyLength(Handle<JSArray> 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<JSArray> 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<JSArray> array, uint32_t length);
// Set the content of the array to the content of storage.
static inline void SetContent(Handle<JSArray> array,
Handle<FixedArrayBase> storage);
// ES6 9.4.2.1
MUST_USE_RESULT static Maybe<bool> DefineOwnProperty(
Isolate* isolate, Handle<JSArray> o, Handle<Object> name,
PropertyDescriptor* desc, ShouldThrow should_throw);
static bool AnythingToArrayLength(Isolate* isolate,
Handle<Object> length_object,
uint32_t* output);
MUST_USE_RESULT static Maybe<bool> ArraySetLength(Isolate* isolate,
Handle<JSArray> 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;
// 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<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
Handle<Map> initial_map);
class JSArrayIterator : public JSObject {
public:
DECL_PRINTER(JSArrayIterator)
DECL_VERIFIER(JSArrayIterator)
DECL_CAST(JSArrayIterator)
// [object]: the [[IteratedObject]] inobject property.
DECL_ACCESSORS(object, Object)
// [index]: The [[ArrayIteratorNextIndex]] inobject property.
DECL_ACCESSORS(index, Object)
// [map]: The Map of the [[IteratedObject]] field at the time the iterator is
// allocated.
DECL_ACCESSORS(object_map, Object)
// Return the ElementsKind that a JSArrayIterator's [[IteratedObject]] is
// expected to have, based on its instance type.
static ElementsKind ElementsKindForInstanceType(InstanceType instance_type);
static const int kIteratedObjectOffset = JSObject::kHeaderSize;
static const int kNextIndexOffset = kIteratedObjectOffset + kPointerSize;
static const int kIteratedObjectMapOffset = kNextIndexOffset + kPointerSize;
static const int kSize = kIteratedObjectMapOffset + 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)
// [allocation_base]: the start of the memory allocation for this array,
// normally equal to backing_store
DECL_ACCESSORS(allocation_base, void)
// [allocation_length]: the size of the memory allocation for this array,
// normally equal to byte_length
inline size_t allocation_length() const;
inline void set_allocation_length(size_t value);
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 has_guard_region() const;
inline void set_has_guard_region(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, AllocationMode mode)
: allocation_base(allocation_base), length(length), mode(mode) {}
void* allocation_base;
size_t length;
AllocationMode mode;
};
void FreeBackingStore();
static void FreeBackingStore(Isolate* isolate, Allocation allocation);
V8_EXPORT_PRIVATE static void Setup(
Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external,
void* data, size_t allocated_length,
SharedFlag shared = SharedFlag::kNotShared);
V8_EXPORT_PRIVATE static void Setup(
Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external,
void* allocation_base, size_t allocation_length, void* data,
size_t byte_length, SharedFlag shared = SharedFlag::kNotShared);
// Returns false if array buffer contents could not be allocated.
// In this case, |array_buffer| will not be set up.
static bool SetupAllocatingData(
Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
size_t allocated_length, bool initialize = true,
SharedFlag shared = SharedFlag::kNotShared) 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 kAllocationBaseOffset = kBackingStoreOffset + kPointerSize;
static const int kAllocationLengthOffset =
kAllocationBaseOffset + kPointerSize;
static const int kBitFieldSlot = kAllocationLengthOffset + kSizetSize;
#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<bool, 1, 1> {};
class IsNeuterable : public BitField<bool, 2, 1> {};
class WasNeutered : public BitField<bool, 3, 1> {};
class IsShared : public BitField<bool, 4, 1> {};
class HasGuardRegion : public BitField<bool, 5, 1> {};
class IsGrowable : public BitField<bool, 6, 1> {};
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
MUST_USE_RESULT static Maybe<bool> DefineOwnProperty(
Isolate* isolate, Handle<JSTypedArray> o, Handle<Object> key,
PropertyDescriptor* desc, ShouldThrow should_throw);
DECL_CAST(JSTypedArray)
ExternalArrayType type();
V8_EXPORT_PRIVATE size_t element_size();
Handle<JSArrayBuffer> GetBuffer();
inline bool HasJSTypedArrayPrototype(Isolate* isolate);
static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate,
Handle<Object> receiver,
const char* method_name);
static inline Handle<JSFunction> DefaultConstructor(
Isolate* isolate, Handle<JSTypedArray> exemplar);
// ES7 section 22.2.4.6 Create ( constructor, argumentList )
static MaybeHandle<JSTypedArray> Create(Isolate* isolate,
Handle<Object> default_ctor, int argc,
Handle<Object>* argv,
const char* method_name);
// ES7 section 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
static MaybeHandle<JSTypedArray> SpeciesCreate(Isolate* isolate,
Handle<JSTypedArray> exemplar,
int argc, Handle<Object>* argv,
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<JSArrayBuffer> MaterializeArrayBuffer(
Handle<JSTypedArray> 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_