// 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/allocation-site.h"
#include "src/objects/fixed-array.h"
#include "src/objects/js-function.h"
#include "src/objects/js-objects.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.
V8_OBJECT class JSArray : public JSObject {
V8_IT_OWN_TYPE;
public:
// [length]: The length property.
inline Tagged<Number> length() const;
inline Tagged<Number> length(RelaxedLoadTag) const;
inline void set_length(Tagged<Number> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Acquire/release semantics on this field are explicitly forbidden to avoid
// confusion, since the default setter uses relaxed semantics. If
// acquire/release semantics ever become necessary, the default setter should
// be reverted to non-atomic behavior, and setters with explicit tags
// introduced and used when required.
Tagged<Number> length(PtrComprCageBase cage_base,
AcquireLoadTag) const = delete;
void set_length(Tagged<Number> value, ReleaseStoreTag tag,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER) = delete;
// 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(Tagged<Smi> length);
static inline bool MayHaveReadOnlyLength(Tagged<Map> js_array_map);
static inline bool HasReadOnlyLength(DirectHandle<JSArray> array);
V8_NOINLINE V8_PRESERVE_MOST static bool HasReadOnlyLengthSlowPath(
DirectHandle<JSArray> array);
static bool WouldChangeReadOnlyLength(DirectHandle<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.
V8_EXPORT_PRIVATE static void Initialize(Isolate* isolate,
DirectHandle<JSArray> array,
uint32_t capacity,
uint32_t 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.
V8_EXPORT_PRIVATE static Maybe<bool> SetLength(Isolate* isolate,
DirectHandle<JSArray> array,
uint32_t length);
// Set the content of the array to the content of storage.
static inline void SetContent(Isolate* isolate, DirectHandle<JSArray> array,
DirectHandle<FixedArrayBase> storage);
// ES6 9.4.2.1
V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty(
Isolate* isolate, DirectHandle<JSArray> o, DirectHandle<Object> name,
PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw);
static bool AnythingToArrayLength(Isolate* isolate,
DirectHandle<Object> length_object,
uint32_t* output);
V8_WARN_UNUSED_RESULT static Maybe<bool> ArraySetLength(
Isolate* isolate, DirectHandle<JSArray> a, PropertyDescriptor* desc,
Maybe<ShouldThrow> should_throw);
// Support for Array.prototype.join().
// Writes a linked list of chunks of strings and separators to a single
// destination string. This helpers assumes the chynk encodes separators in
// two ways:
// 1) Explicitly with a smi, whos value represents the number of repeated
// separators.
// 2) Implicitly between two consecutive strings a single separator.
// The 0-th element stores a link to the next chunk (FixedArray or undefined).
//
// In addition repeated strings are represented by a negative smi, indicating
// how many times the previously written string has to be repeated.
//
// Here are some input/output examples given the separator string is ',':
//
// [undefined, 1, 'hello', 2, 'world', 1] => ',hello,,world,'
// [undefined, 'hello', 'world'] => 'hello,world'
// [undefined, 'hello', -2, 'world'] => 'hello,hello,hello,world'
// [[undefined, 'a', 'b'], 'c', 'd'] => 'a,b,c,d'
//
// To avoid any allocations, this helper assumes the destination string is the
// exact length necessary to write the strings and separators from the fixed
// array.
// Since this is called via ExternalReferences, it uses raw Address values:
// - {raw_fixed_array} is a tagged FixedArray pointer.
// - {raw_separator} and {raw_dest} are tagged String pointers.
// - Returns a tagged String pointer.
static Address ArrayJoinConcatToSequentialString(
Isolate* isolate, Address raw_list_head, uintptr_t raw_last_chunk_length,
Address raw_separator, Address raw_dest);
// 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);
// Dispatched behavior.
DECL_PRINTER(JSArray)
DECL_VERIFIER(JSArray)
// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
static const int kLengthDescriptorIndex = 0;
// Max. number of elements being copied in Array builtins.
static const int kMaxCopyElements = 100;
// Maximum array length for which Maglev/TurboFan inline an insertion sort
// instead of calling the generic PowerSort builtin. PowerSort itself uses
// BinaryInsertionSort below this threshold too.
static constexpr int kMaxInlineSortLength = 16;
// Valid array indices range from +0 <= i < 2^32 - 1 (kMaxUInt32).
static constexpr uint32_t kMaxArrayLength = JSObject::kMaxElementCount;
static constexpr uint32_t kMaxArrayIndex = JSObject::kMaxElementIndex;
static_assert(kMaxArrayLength == kMaxUInt32);
static_assert(kMaxArrayIndex == kMaxUInt32 - 1);
// This constant is somewhat arbitrary. Any large enough value would work.
static constexpr uint32_t kMaxFastArrayLength =
V8_LOWER_LIMITS_MODE_BOOL ? (1 * 1024 * 1024) : (32 * 1024 * 1024);
static_assert(kMaxFastArrayLength <= kMaxArrayLength);
static_assert(kMaxFastArrayLength <= kMaxFixedArrayCapacity);
// Min. stack size for detecting an Array.prototype.join() call cycle.
static const uint32_t kMinJoinStackSize = 2;
static const int kHeaderSize;
static const int kInitialMaxFastElementArray;
public:
TaggedMember<Number> length_;
} V8_OBJECT_END;
inline constexpr int JSArray::kHeaderSize = sizeof(JSArray);
inline constexpr int JSArray::kInitialMaxFastElementArray =
(kMaxRegularHeapObjectSize - static_cast<int>(sizeof(FixedArray)) -
JSArray::kHeaderSize - static_cast<int>(sizeof(AllocationMemento))) >>
kDoubleSizeLog2;
// The JSArrayIterator describes JavaScript Array Iterators Objects, as
// defined in https://tc39.es/ecma262/#sec-array-iterator-objects.
V8_OBJECT class JSArrayIterator : public JSObject {
public:
inline Tagged<JSReceiver> iterated_object() const;
inline void set_iterated_object(Tagged<JSReceiver> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Tagged<Number> next_index() const;
inline void set_next_index(Tagged<Number> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
DECL_PRINTER(JSArrayIterator)
DECL_VERIFIER(JSArrayIterator)
// [kind]: the [[ArrayIterationKind]] inobject property.
inline IterationKind kind() const;
inline void set_kind(IterationKind kind);
private:
inline int raw_kind() const;
inline void set_raw_kind(int value);
public:
TaggedMember<JSReceiver> iterated_object_;
TaggedMember<Number> next_index_;
// SmiTagged<IterationKind>.
TaggedMember<Smi> kind_;
} V8_OBJECT_END;
// Helper class for JSArrays that are template literal objects
V8_OBJECT class TemplateLiteralObject : public JSArray {
V8_IT_REUSE_PARENT;
V8_IT_NO_AUTO_CHECKER;
public:
inline Tagged<JSArray> raw() const;
inline void set_raw(Tagged<JSArray> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline int function_literal_id() const;
inline void set_function_literal_id(int value);
inline int slot_id() const;
inline void set_slot_id(int value);
static const int kHeaderSize;
public:
TaggedMember<JSArray> raw_;
TaggedMember<Smi> function_literal_id_;
TaggedMember<Smi> slot_id_;
} V8_OBJECT_END;
inline constexpr int TemplateLiteralObject::kHeaderSize =
sizeof(TemplateLiteralObject);
V8_OBJECT class JSArrayConstructor : public JSFunctionWithPrototype {
} V8_OBJECT_END;
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_ARRAY_H_