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