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_FIXED_ARRAY_INL_H_
6 #define V8_OBJECTS_FIXED_ARRAY_INL_H_
7 
8 #include "src/objects.h"
9 
10 // Has to be the last include (doesn't have include guards):
11 #include "src/objects/object-macros.h"
12 
13 namespace v8 {
14 namespace internal {
15 
TYPE_CHECKER(ByteArray,BYTE_ARRAY_TYPE)16 TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE)
17 TYPE_CHECKER(FixedArrayExact, FIXED_ARRAY_TYPE)
18 TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE)
19 TYPE_CHECKER(FixedArrayOfWeakCells, FIXED_ARRAY_TYPE)
20 TYPE_CHECKER(WeakArrayList, WEAK_ARRAY_LIST_TYPE)
21 
22 CAST_ACCESSOR(ArrayList)
23 CAST_ACCESSOR(ByteArray)
24 CAST_ACCESSOR(FixedArray)
25 CAST_ACCESSOR(FixedArrayBase)
26 CAST_ACCESSOR(FixedDoubleArray)
27 CAST_ACCESSOR(FixedTypedArrayBase)
28 CAST_ACCESSOR(TemplateList)
29 CAST_ACCESSOR(FixedArrayOfWeakCells)
30 CAST_ACCESSOR(WeakFixedArray)
31 CAST_ACCESSOR(WeakArrayList)
32 
33 SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
34 SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
35 SMI_ACCESSORS(WeakFixedArray, length, kLengthOffset)
36 SYNCHRONIZED_SMI_ACCESSORS(WeakFixedArray, length, kLengthOffset)
37 
38 SMI_ACCESSORS(WeakArrayList, capacity, kCapacityOffset)
39 SYNCHRONIZED_SMI_ACCESSORS(WeakArrayList, capacity, kCapacityOffset)
40 SMI_ACCESSORS(WeakArrayList, length, kLengthOffset)
41 
42 Object* FixedArrayBase::unchecked_synchronized_length() const {
43   return ACQUIRE_READ_FIELD(this, kLengthOffset);
44 }
45 
ACCESSORS(FixedTypedArrayBase,base_pointer,Object,kBasePointerOffset)46 ACCESSORS(FixedTypedArrayBase, base_pointer, Object, kBasePointerOffset)
47 
48 Object** FixedArray::GetFirstElementAddress() {
49   return reinterpret_cast<Object**>(FIELD_ADDR(this, OffsetOfElementAt(0)));
50 }
51 
ContainsOnlySmisOrHoles()52 bool FixedArray::ContainsOnlySmisOrHoles() {
53   Object* the_hole = GetHeap()->the_hole_value();
54   Object** current = GetFirstElementAddress();
55   for (int i = 0; i < length(); ++i) {
56     Object* candidate = *current++;
57     if (!candidate->IsSmi() && candidate != the_hole) return false;
58   }
59   return true;
60 }
61 
get(int index)62 Object* FixedArray::get(int index) const {
63   SLOW_DCHECK(index >= 0 && index < this->length());
64   return RELAXED_READ_FIELD(this, kHeaderSize + index * kPointerSize);
65 }
66 
get(FixedArray * array,int index,Isolate * isolate)67 Handle<Object> FixedArray::get(FixedArray* array, int index, Isolate* isolate) {
68   return handle(array->get(index), isolate);
69 }
70 
71 template <class T>
GetValue(Isolate * isolate,int index)72 MaybeHandle<T> FixedArray::GetValue(Isolate* isolate, int index) const {
73   Object* obj = get(index);
74   if (obj->IsUndefined(isolate)) return MaybeHandle<T>();
75   return Handle<T>(T::cast(obj), isolate);
76 }
77 
78 template <class T>
GetValueChecked(Isolate * isolate,int index)79 Handle<T> FixedArray::GetValueChecked(Isolate* isolate, int index) const {
80   Object* obj = get(index);
81   CHECK(!obj->IsUndefined(isolate));
82   return Handle<T>(T::cast(obj), isolate);
83 }
84 
is_the_hole(Isolate * isolate,int index)85 bool FixedArray::is_the_hole(Isolate* isolate, int index) {
86   return get(index)->IsTheHole(isolate);
87 }
88 
set(int index,Smi * value)89 void FixedArray::set(int index, Smi* value) {
90   DCHECK_NE(map(), GetHeap()->fixed_cow_array_map());
91   DCHECK_LT(index, this->length());
92   DCHECK(reinterpret_cast<Object*>(value)->IsSmi());
93   int offset = kHeaderSize + index * kPointerSize;
94   RELAXED_WRITE_FIELD(this, offset, value);
95 }
96 
set(int index,Object * value)97 void FixedArray::set(int index, Object* value) {
98   DCHECK_NE(GetHeap()->fixed_cow_array_map(), map());
99   DCHECK(IsFixedArray());
100   DCHECK_GE(index, 0);
101   DCHECK_LT(index, this->length());
102   int offset = kHeaderSize + index * kPointerSize;
103   RELAXED_WRITE_FIELD(this, offset, value);
104   WRITE_BARRIER(GetHeap(), this, offset, value);
105 }
106 
set(int index,Object * value,WriteBarrierMode mode)107 void FixedArray::set(int index, Object* value, WriteBarrierMode mode) {
108   DCHECK_NE(map(), GetHeap()->fixed_cow_array_map());
109   DCHECK_GE(index, 0);
110   DCHECK_LT(index, this->length());
111   int offset = kHeaderSize + index * kPointerSize;
112   RELAXED_WRITE_FIELD(this, offset, value);
113   CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, value, mode);
114 }
115 
NoWriteBarrierSet(FixedArray * array,int index,Object * value)116 void FixedArray::NoWriteBarrierSet(FixedArray* array, int index,
117                                    Object* value) {
118   DCHECK_NE(array->map(), array->GetHeap()->fixed_cow_array_map());
119   DCHECK_GE(index, 0);
120   DCHECK_LT(index, array->length());
121   DCHECK(!array->GetHeap()->InNewSpace(value));
122   RELAXED_WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value);
123 }
124 
set_undefined(int index)125 void FixedArray::set_undefined(int index) {
126   set_undefined(GetIsolate(), index);
127 }
128 
set_undefined(Isolate * isolate,int index)129 void FixedArray::set_undefined(Isolate* isolate, int index) {
130   FixedArray::NoWriteBarrierSet(this, index,
131                                 isolate->heap()->undefined_value());
132 }
133 
set_null(int index)134 void FixedArray::set_null(int index) { set_null(GetIsolate(), index); }
135 
set_null(Isolate * isolate,int index)136 void FixedArray::set_null(Isolate* isolate, int index) {
137   FixedArray::NoWriteBarrierSet(this, index, isolate->heap()->null_value());
138 }
139 
set_the_hole(int index)140 void FixedArray::set_the_hole(int index) { set_the_hole(GetIsolate(), index); }
141 
set_the_hole(Isolate * isolate,int index)142 void FixedArray::set_the_hole(Isolate* isolate, int index) {
143   FixedArray::NoWriteBarrierSet(this, index, isolate->heap()->the_hole_value());
144 }
145 
FillWithHoles(int from,int to)146 void FixedArray::FillWithHoles(int from, int to) {
147   Isolate* isolate = GetIsolate();
148   for (int i = from; i < to; i++) {
149     set_the_hole(isolate, i);
150   }
151 }
152 
data_start()153 Object** FixedArray::data_start() {
154   return HeapObject::RawField(this, OffsetOfElementAt(0));
155 }
156 
RawFieldOfElementAt(int index)157 Object** FixedArray::RawFieldOfElementAt(int index) {
158   return HeapObject::RawField(this, OffsetOfElementAt(index));
159 }
160 
get_scalar(int index)161 double FixedDoubleArray::get_scalar(int index) {
162   DCHECK(map() != GetHeap()->fixed_cow_array_map() &&
163          map() != GetHeap()->fixed_array_map());
164   DCHECK(index >= 0 && index < this->length());
165   DCHECK(!is_the_hole(index));
166   return READ_DOUBLE_FIELD(this, kHeaderSize + index * kDoubleSize);
167 }
168 
get_representation(int index)169 uint64_t FixedDoubleArray::get_representation(int index) {
170   DCHECK(map() != GetHeap()->fixed_cow_array_map() &&
171          map() != GetHeap()->fixed_array_map());
172   DCHECK(index >= 0 && index < this->length());
173   int offset = kHeaderSize + index * kDoubleSize;
174   return READ_UINT64_FIELD(this, offset);
175 }
176 
get(FixedDoubleArray * array,int index,Isolate * isolate)177 Handle<Object> FixedDoubleArray::get(FixedDoubleArray* array, int index,
178                                      Isolate* isolate) {
179   if (array->is_the_hole(index)) {
180     return isolate->factory()->the_hole_value();
181   } else {
182     return isolate->factory()->NewNumber(array->get_scalar(index));
183   }
184 }
185 
set(int index,double value)186 void FixedDoubleArray::set(int index, double value) {
187   DCHECK(map() != GetHeap()->fixed_cow_array_map() &&
188          map() != GetHeap()->fixed_array_map());
189   int offset = kHeaderSize + index * kDoubleSize;
190   if (std::isnan(value)) {
191     WRITE_DOUBLE_FIELD(this, offset, std::numeric_limits<double>::quiet_NaN());
192   } else {
193     WRITE_DOUBLE_FIELD(this, offset, value);
194   }
195   DCHECK(!is_the_hole(index));
196 }
197 
set_the_hole(Isolate * isolate,int index)198 void FixedDoubleArray::set_the_hole(Isolate* isolate, int index) {
199   set_the_hole(index);
200 }
201 
set_the_hole(int index)202 void FixedDoubleArray::set_the_hole(int index) {
203   DCHECK(map() != GetHeap()->fixed_cow_array_map() &&
204          map() != GetHeap()->fixed_array_map());
205   int offset = kHeaderSize + index * kDoubleSize;
206   WRITE_UINT64_FIELD(this, offset, kHoleNanInt64);
207 }
208 
is_the_hole(Isolate * isolate,int index)209 bool FixedDoubleArray::is_the_hole(Isolate* isolate, int index) {
210   return is_the_hole(index);
211 }
212 
is_the_hole(int index)213 bool FixedDoubleArray::is_the_hole(int index) {
214   return get_representation(index) == kHoleNanInt64;
215 }
216 
data_start()217 double* FixedDoubleArray::data_start() {
218   return reinterpret_cast<double*>(FIELD_ADDR(this, kHeaderSize));
219 }
220 
FillWithHoles(int from,int to)221 void FixedDoubleArray::FillWithHoles(int from, int to) {
222   for (int i = from; i < to; i++) {
223     set_the_hole(i);
224   }
225 }
226 
Get(int index)227 MaybeObject* WeakFixedArray::Get(int index) const {
228   SLOW_DCHECK(index >= 0 && index < this->length());
229   return RELAXED_READ_WEAK_FIELD(this, OffsetOfElementAt(index));
230 }
231 
Set(int index,MaybeObject * value)232 void WeakFixedArray::Set(int index, MaybeObject* value) {
233   DCHECK_GE(index, 0);
234   DCHECK_LT(index, length());
235   int offset = OffsetOfElementAt(index);
236   RELAXED_WRITE_FIELD(this, offset, value);
237   WEAK_WRITE_BARRIER(GetHeap(), this, offset, value);
238 }
239 
Set(int index,MaybeObject * value,WriteBarrierMode mode)240 void WeakFixedArray::Set(int index, MaybeObject* value, WriteBarrierMode mode) {
241   DCHECK_GE(index, 0);
242   DCHECK_LT(index, length());
243   int offset = OffsetOfElementAt(index);
244   RELAXED_WRITE_FIELD(this, offset, value);
245   CONDITIONAL_WEAK_WRITE_BARRIER(GetHeap(), this, offset, value, mode);
246 }
247 
data_start()248 MaybeObject** WeakFixedArray::data_start() {
249   return HeapObject::RawMaybeWeakField(this, kHeaderSize);
250 }
251 
RawFieldOfElementAt(int index)252 MaybeObject** WeakFixedArray::RawFieldOfElementAt(int index) {
253   return HeapObject::RawMaybeWeakField(this, OffsetOfElementAt(index));
254 }
255 
Get(int index)256 MaybeObject* WeakArrayList::Get(int index) const {
257   SLOW_DCHECK(index >= 0 && index < this->capacity());
258   return RELAXED_READ_WEAK_FIELD(this, OffsetOfElementAt(index));
259 }
260 
Set(int index,MaybeObject * value,WriteBarrierMode mode)261 void WeakArrayList::Set(int index, MaybeObject* value, WriteBarrierMode mode) {
262   DCHECK_GE(index, 0);
263   DCHECK_LT(index, this->capacity());
264   int offset = OffsetOfElementAt(index);
265   RELAXED_WRITE_FIELD(this, offset, value);
266   CONDITIONAL_WEAK_WRITE_BARRIER(GetHeap(), this, offset, value, mode);
267 }
268 
data_start()269 MaybeObject** WeakArrayList::data_start() {
270   return HeapObject::RawMaybeWeakField(this, kHeaderSize);
271 }
272 
Get(int index)273 Object* FixedArrayOfWeakCells::Get(int index) const {
274   Object* raw = FixedArray::cast(this)->get(index + kFirstIndex);
275   if (raw->IsSmi()) return raw;
276   DCHECK(raw->IsWeakCell());
277   return WeakCell::cast(raw)->value();
278 }
279 
IsEmptySlot(int index)280 bool FixedArrayOfWeakCells::IsEmptySlot(int index) const {
281   DCHECK(index < Length());
282   return Get(index)->IsSmi();
283 }
284 
Clear(int index)285 void FixedArrayOfWeakCells::Clear(int index) {
286   FixedArray::cast(this)->set(index + kFirstIndex, Smi::kZero);
287 }
288 
Length()289 int FixedArrayOfWeakCells::Length() const {
290   return FixedArray::cast(this)->length() - kFirstIndex;
291 }
292 
last_used_index()293 int FixedArrayOfWeakCells::last_used_index() const {
294   return Smi::ToInt(FixedArray::cast(this)->get(kLastUsedIndexIndex));
295 }
296 
set_last_used_index(int index)297 void FixedArrayOfWeakCells::set_last_used_index(int index) {
298   FixedArray::cast(this)->set(kLastUsedIndexIndex, Smi::FromInt(index));
299 }
300 
301 template <class T>
Next()302 T* FixedArrayOfWeakCells::Iterator::Next() {
303   if (list_ != nullptr) {
304     // Assert that list did not change during iteration.
305     DCHECK_EQ(last_used_index_, list_->last_used_index());
306     while (index_ < list_->Length()) {
307       Object* item = list_->Get(index_++);
308       if (item != Empty()) return T::cast(item);
309     }
310     list_ = nullptr;
311   }
312   return nullptr;
313 }
314 
Length()315 int ArrayList::Length() const {
316   if (FixedArray::cast(this)->length() == 0) return 0;
317   return Smi::ToInt(FixedArray::cast(this)->get(kLengthIndex));
318 }
319 
SetLength(int length)320 void ArrayList::SetLength(int length) {
321   return FixedArray::cast(this)->set(kLengthIndex, Smi::FromInt(length));
322 }
323 
Get(int index)324 Object* ArrayList::Get(int index) const {
325   return FixedArray::cast(this)->get(kFirstIndex + index);
326 }
327 
Slot(int index)328 Object** ArrayList::Slot(int index) {
329   return data_start() + kFirstIndex + index;
330 }
331 
Set(int index,Object * obj,WriteBarrierMode mode)332 void ArrayList::Set(int index, Object* obj, WriteBarrierMode mode) {
333   FixedArray::cast(this)->set(kFirstIndex + index, obj, mode);
334 }
335 
Clear(int index,Object * undefined)336 void ArrayList::Clear(int index, Object* undefined) {
337   DCHECK(undefined->IsUndefined(GetIsolate()));
338   FixedArray::cast(this)->set(kFirstIndex + index, undefined,
339                               SKIP_WRITE_BARRIER);
340 }
341 
Size()342 int ByteArray::Size() { return RoundUp(length() + kHeaderSize, kPointerSize); }
343 
get(int index)344 byte ByteArray::get(int index) const {
345   DCHECK(index >= 0 && index < this->length());
346   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
347 }
348 
set(int index,byte value)349 void ByteArray::set(int index, byte value) {
350   DCHECK(index >= 0 && index < this->length());
351   WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
352 }
353 
copy_in(int index,const byte * buffer,int length)354 void ByteArray::copy_in(int index, const byte* buffer, int length) {
355   DCHECK(index >= 0 && length >= 0 && length <= kMaxInt - index &&
356          index + length <= this->length());
357   Address dst_addr = FIELD_ADDR(this, kHeaderSize + index * kCharSize);
358   memcpy(reinterpret_cast<void*>(dst_addr), buffer, length);
359 }
360 
copy_out(int index,byte * buffer,int length)361 void ByteArray::copy_out(int index, byte* buffer, int length) {
362   DCHECK(index >= 0 && length >= 0 && length <= kMaxInt - index &&
363          index + length <= this->length());
364   Address src_addr = FIELD_ADDR(this, kHeaderSize + index * kCharSize);
365   memcpy(buffer, reinterpret_cast<void*>(src_addr), length);
366 }
367 
get_int(int index)368 int ByteArray::get_int(int index) const {
369   DCHECK(index >= 0 && index < this->length() / kIntSize);
370   return READ_INT_FIELD(this, kHeaderSize + index * kIntSize);
371 }
372 
set_int(int index,int value)373 void ByteArray::set_int(int index, int value) {
374   DCHECK(index >= 0 && index < this->length() / kIntSize);
375   WRITE_INT_FIELD(this, kHeaderSize + index * kIntSize, value);
376 }
377 
get_uint32(int index)378 uint32_t ByteArray::get_uint32(int index) const {
379   DCHECK(index >= 0 && index < this->length() / kUInt32Size);
380   return READ_UINT32_FIELD(this, kHeaderSize + index * kUInt32Size);
381 }
382 
set_uint32(int index,uint32_t value)383 void ByteArray::set_uint32(int index, uint32_t value) {
384   DCHECK(index >= 0 && index < this->length() / kUInt32Size);
385   WRITE_UINT32_FIELD(this, kHeaderSize + index * kUInt32Size, value);
386 }
387 
clear_padding()388 void ByteArray::clear_padding() {
389   int data_size = length() + kHeaderSize;
390   memset(reinterpret_cast<void*>(address() + data_size), 0, Size() - data_size);
391 }
392 
FromDataStartAddress(Address address)393 ByteArray* ByteArray::FromDataStartAddress(Address address) {
394   DCHECK_TAG_ALIGNED(address);
395   return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag);
396 }
397 
DataSize()398 int ByteArray::DataSize() const { return RoundUp(length(), kPointerSize); }
399 
ByteArraySize()400 int ByteArray::ByteArraySize() { return SizeFor(this->length()); }
401 
GetDataStartAddress()402 byte* ByteArray::GetDataStartAddress() {
403   return reinterpret_cast<byte*>(address() + kHeaderSize);
404 }
405 
406 template <class T>
cast(Object * object)407 PodArray<T>* PodArray<T>::cast(Object* object) {
408   SLOW_DCHECK(object->IsByteArray());
409   return reinterpret_cast<PodArray<T>*>(object);
410 }
411 template <class T>
cast(const Object * object)412 const PodArray<T>* PodArray<T>::cast(const Object* object) {
413   SLOW_DCHECK(object->IsByteArray());
414   return reinterpret_cast<const PodArray<T>*>(object);
415 }
416 
417 // static
418 template <class T>
New(Isolate * isolate,int length,PretenureFlag pretenure)419 Handle<PodArray<T>> PodArray<T>::New(Isolate* isolate, int length,
420                                      PretenureFlag pretenure) {
421   return Handle<PodArray<T>>::cast(
422       isolate->factory()->NewByteArray(length * sizeof(T), pretenure));
423 }
424 
external_pointer()425 void* FixedTypedArrayBase::external_pointer() const {
426   intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset);
427   return reinterpret_cast<void*>(ptr);
428 }
429 
set_external_pointer(void * value,WriteBarrierMode mode)430 void FixedTypedArrayBase::set_external_pointer(void* value,
431                                                WriteBarrierMode mode) {
432   intptr_t ptr = reinterpret_cast<intptr_t>(value);
433   WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr);
434 }
435 
DataPtr()436 void* FixedTypedArrayBase::DataPtr() {
437   return reinterpret_cast<void*>(
438       reinterpret_cast<intptr_t>(base_pointer()) +
439       reinterpret_cast<intptr_t>(external_pointer()));
440 }
441 
ElementSize(InstanceType type)442 int FixedTypedArrayBase::ElementSize(InstanceType type) {
443   int element_size;
444   switch (type) {
445 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
446   case FIXED_##TYPE##_ARRAY_TYPE:                       \
447     element_size = size;                                \
448     break;
449 
450     TYPED_ARRAYS(TYPED_ARRAY_CASE)
451 #undef TYPED_ARRAY_CASE
452     default:
453       UNREACHABLE();
454   }
455   return element_size;
456 }
457 
DataSize(InstanceType type)458 int FixedTypedArrayBase::DataSize(InstanceType type) const {
459   if (base_pointer() == Smi::kZero) return 0;
460   return length() * ElementSize(type);
461 }
462 
DataSize()463 int FixedTypedArrayBase::DataSize() const {
464   return DataSize(map()->instance_type());
465 }
466 
ByteLength()467 size_t FixedTypedArrayBase::ByteLength() const {
468   return static_cast<size_t>(length()) *
469          static_cast<size_t>(ElementSize(map()->instance_type()));
470 }
471 
size()472 int FixedTypedArrayBase::size() const {
473   return OBJECT_POINTER_ALIGN(kDataOffset + DataSize());
474 }
475 
TypedArraySize(InstanceType type)476 int FixedTypedArrayBase::TypedArraySize(InstanceType type) const {
477   return OBJECT_POINTER_ALIGN(kDataOffset + DataSize(type));
478 }
479 
480 // static
TypedArraySize(InstanceType type,int length)481 int FixedTypedArrayBase::TypedArraySize(InstanceType type, int length) {
482   return OBJECT_POINTER_ALIGN(kDataOffset + length * ElementSize(type));
483 }
484 
defaultValue()485 uint8_t Uint8ArrayTraits::defaultValue() { return 0; }
486 
defaultValue()487 uint8_t Uint8ClampedArrayTraits::defaultValue() { return 0; }
488 
defaultValue()489 int8_t Int8ArrayTraits::defaultValue() { return 0; }
490 
defaultValue()491 uint16_t Uint16ArrayTraits::defaultValue() { return 0; }
492 
defaultValue()493 int16_t Int16ArrayTraits::defaultValue() { return 0; }
494 
defaultValue()495 uint32_t Uint32ArrayTraits::defaultValue() { return 0; }
496 
defaultValue()497 int32_t Int32ArrayTraits::defaultValue() { return 0; }
498 
defaultValue()499 float Float32ArrayTraits::defaultValue() {
500   return std::numeric_limits<float>::quiet_NaN();
501 }
502 
defaultValue()503 double Float64ArrayTraits::defaultValue() {
504   return std::numeric_limits<double>::quiet_NaN();
505 }
506 
507 template <class Traits>
get_scalar(int index)508 typename Traits::ElementType FixedTypedArray<Traits>::get_scalar(int index) {
509   DCHECK((index >= 0) && (index < this->length()));
510   return FixedTypedArray<Traits>::get_scalar_from_data_ptr(DataPtr(), index);
511 }
512 
513 // static
514 template <class Traits>
get_scalar_from_data_ptr(void * data_ptr,int index)515 typename Traits::ElementType FixedTypedArray<Traits>::get_scalar_from_data_ptr(
516     void* data_ptr, int index) {
517   typename Traits::ElementType* ptr = reinterpret_cast<ElementType*>(data_ptr);
518   // The JavaScript memory model allows for racy reads and writes to a
519   // SharedArrayBuffer's backing store, which will always be a FixedTypedArray.
520   // ThreadSanitizer will catch these racy accesses and warn about them, so we
521   // disable TSAN for these reads and writes using annotations.
522   //
523   // We don't use relaxed atomics here, as it is not a requirement of the
524   // JavaScript memory model to have tear-free reads of overlapping accesses,
525   // and using relaxed atomics may introduce overhead.
526   TSAN_ANNOTATE_IGNORE_READS_BEGIN;
527   auto result = ptr[index];
528   TSAN_ANNOTATE_IGNORE_READS_END;
529   return result;
530 }
531 
532 template <class Traits>
set(int index,ElementType value)533 void FixedTypedArray<Traits>::set(int index, ElementType value) {
534   CHECK((index >= 0) && (index < this->length()));
535   // See the comment in FixedTypedArray<Traits>::get_scalar.
536   auto* ptr = reinterpret_cast<ElementType*>(DataPtr());
537   TSAN_ANNOTATE_IGNORE_WRITES_BEGIN;
538   ptr[index] = value;
539   TSAN_ANNOTATE_IGNORE_WRITES_END;
540 }
541 
542 template <class Traits>
from(int value)543 typename Traits::ElementType FixedTypedArray<Traits>::from(int value) {
544   return static_cast<ElementType>(value);
545 }
546 
547 template <>
from(int value)548 inline uint8_t FixedTypedArray<Uint8ClampedArrayTraits>::from(int value) {
549   if (value < 0) return 0;
550   if (value > 0xFF) return 0xFF;
551   return static_cast<uint8_t>(value);
552 }
553 
554 template <>
from(int value)555 inline int64_t FixedTypedArray<BigInt64ArrayTraits>::from(int value) {
556   UNREACHABLE();
557 }
558 
559 template <>
from(int value)560 inline uint64_t FixedTypedArray<BigUint64ArrayTraits>::from(int value) {
561   UNREACHABLE();
562 }
563 
564 template <class Traits>
from(uint32_t value)565 typename Traits::ElementType FixedTypedArray<Traits>::from(uint32_t value) {
566   return static_cast<ElementType>(value);
567 }
568 
569 template <>
from(uint32_t value)570 inline uint8_t FixedTypedArray<Uint8ClampedArrayTraits>::from(uint32_t value) {
571   // We need this special case for Uint32 -> Uint8Clamped, because the highest
572   // Uint32 values will be negative as an int, clamping to 0, rather than 255.
573   if (value > 0xFF) return 0xFF;
574   return static_cast<uint8_t>(value);
575 }
576 
577 template <>
from(uint32_t value)578 inline int64_t FixedTypedArray<BigInt64ArrayTraits>::from(uint32_t value) {
579   UNREACHABLE();
580 }
581 
582 template <>
from(uint32_t value)583 inline uint64_t FixedTypedArray<BigUint64ArrayTraits>::from(uint32_t value) {
584   UNREACHABLE();
585 }
586 
587 template <class Traits>
from(double value)588 typename Traits::ElementType FixedTypedArray<Traits>::from(double value) {
589   return static_cast<ElementType>(DoubleToInt32(value));
590 }
591 
592 template <>
from(double value)593 inline uint8_t FixedTypedArray<Uint8ClampedArrayTraits>::from(double value) {
594   // Handle NaNs and less than zero values which clamp to zero.
595   if (!(value > 0)) return 0;
596   if (value > 0xFF) return 0xFF;
597   return static_cast<uint8_t>(lrint(value));
598 }
599 
600 template <>
from(double value)601 inline int64_t FixedTypedArray<BigInt64ArrayTraits>::from(double value) {
602   UNREACHABLE();
603 }
604 
605 template <>
from(double value)606 inline uint64_t FixedTypedArray<BigUint64ArrayTraits>::from(double value) {
607   UNREACHABLE();
608 }
609 
610 template <>
from(double value)611 inline float FixedTypedArray<Float32ArrayTraits>::from(double value) {
612   return static_cast<float>(value);
613 }
614 
615 template <>
from(double value)616 inline double FixedTypedArray<Float64ArrayTraits>::from(double value) {
617   return value;
618 }
619 
620 template <class Traits>
from(int64_t value)621 typename Traits::ElementType FixedTypedArray<Traits>::from(int64_t value) {
622   UNREACHABLE();
623 }
624 
625 template <class Traits>
from(uint64_t value)626 typename Traits::ElementType FixedTypedArray<Traits>::from(uint64_t value) {
627   UNREACHABLE();
628 }
629 
630 template <>
from(int64_t value)631 inline int64_t FixedTypedArray<BigInt64ArrayTraits>::from(int64_t value) {
632   return value;
633 }
634 
635 template <>
from(uint64_t value)636 inline uint64_t FixedTypedArray<BigUint64ArrayTraits>::from(uint64_t value) {
637   return value;
638 }
639 
640 template <>
from(int64_t value)641 inline uint64_t FixedTypedArray<BigUint64ArrayTraits>::from(int64_t value) {
642   return static_cast<uint64_t>(value);
643 }
644 
645 template <>
from(uint64_t value)646 inline int64_t FixedTypedArray<BigInt64ArrayTraits>::from(uint64_t value) {
647   return static_cast<int64_t>(value);
648 }
649 
650 template <class Traits>
FromHandle(Handle<Object> value,bool * lossless)651 typename Traits::ElementType FixedTypedArray<Traits>::FromHandle(
652     Handle<Object> value, bool* lossless) {
653   if (value->IsSmi()) {
654     return from(Smi::ToInt(*value));
655   }
656   DCHECK(value->IsHeapNumber());
657   return from(HeapNumber::cast(*value)->value());
658 }
659 
660 template <>
FromHandle(Handle<Object> value,bool * lossless)661 inline int64_t FixedTypedArray<BigInt64ArrayTraits>::FromHandle(
662     Handle<Object> value, bool* lossless) {
663   DCHECK(value->IsBigInt());
664   return BigInt::cast(*value)->AsInt64(lossless);
665 }
666 
667 template <>
FromHandle(Handle<Object> value,bool * lossless)668 inline uint64_t FixedTypedArray<BigUint64ArrayTraits>::FromHandle(
669     Handle<Object> value, bool* lossless) {
670   DCHECK(value->IsBigInt());
671   return BigInt::cast(*value)->AsUint64(lossless);
672 }
673 
674 template <class Traits>
get(FixedTypedArray<Traits> * array,int index)675 Handle<Object> FixedTypedArray<Traits>::get(FixedTypedArray<Traits>* array,
676                                             int index) {
677   return Traits::ToHandle(array->GetIsolate(), array->get_scalar(index));
678 }
679 
680 template <class Traits>
SetValue(uint32_t index,Object * value)681 void FixedTypedArray<Traits>::SetValue(uint32_t index, Object* value) {
682   ElementType cast_value = Traits::defaultValue();
683   if (value->IsSmi()) {
684     int int_value = Smi::ToInt(value);
685     cast_value = from(int_value);
686   } else if (value->IsHeapNumber()) {
687     double double_value = HeapNumber::cast(value)->value();
688     cast_value = from(double_value);
689   } else {
690     // Clamp undefined to the default value. All other types have been
691     // converted to a number type further up in the call chain.
692     DCHECK(value->IsUndefined(GetIsolate()));
693   }
694   set(index, cast_value);
695 }
696 
697 template <>
SetValue(uint32_t index,Object * value)698 inline void FixedTypedArray<BigInt64ArrayTraits>::SetValue(uint32_t index,
699                                                            Object* value) {
700   DCHECK(value->IsBigInt());
701   set(index, BigInt::cast(value)->AsInt64());
702 }
703 
704 template <>
SetValue(uint32_t index,Object * value)705 inline void FixedTypedArray<BigUint64ArrayTraits>::SetValue(uint32_t index,
706                                                             Object* value) {
707   DCHECK(value->IsBigInt());
708   set(index, BigInt::cast(value)->AsUint64());
709 }
710 
ToHandle(Isolate * isolate,uint8_t scalar)711 Handle<Object> Uint8ArrayTraits::ToHandle(Isolate* isolate, uint8_t scalar) {
712   return handle(Smi::FromInt(scalar), isolate);
713 }
714 
ToHandle(Isolate * isolate,uint8_t scalar)715 Handle<Object> Uint8ClampedArrayTraits::ToHandle(Isolate* isolate,
716                                                  uint8_t scalar) {
717   return handle(Smi::FromInt(scalar), isolate);
718 }
719 
ToHandle(Isolate * isolate,int8_t scalar)720 Handle<Object> Int8ArrayTraits::ToHandle(Isolate* isolate, int8_t scalar) {
721   return handle(Smi::FromInt(scalar), isolate);
722 }
723 
ToHandle(Isolate * isolate,uint16_t scalar)724 Handle<Object> Uint16ArrayTraits::ToHandle(Isolate* isolate, uint16_t scalar) {
725   return handle(Smi::FromInt(scalar), isolate);
726 }
727 
ToHandle(Isolate * isolate,int16_t scalar)728 Handle<Object> Int16ArrayTraits::ToHandle(Isolate* isolate, int16_t scalar) {
729   return handle(Smi::FromInt(scalar), isolate);
730 }
731 
ToHandle(Isolate * isolate,uint32_t scalar)732 Handle<Object> Uint32ArrayTraits::ToHandle(Isolate* isolate, uint32_t scalar) {
733   return isolate->factory()->NewNumberFromUint(scalar);
734 }
735 
ToHandle(Isolate * isolate,int32_t scalar)736 Handle<Object> Int32ArrayTraits::ToHandle(Isolate* isolate, int32_t scalar) {
737   return isolate->factory()->NewNumberFromInt(scalar);
738 }
739 
ToHandle(Isolate * isolate,float scalar)740 Handle<Object> Float32ArrayTraits::ToHandle(Isolate* isolate, float scalar) {
741   return isolate->factory()->NewNumber(scalar);
742 }
743 
ToHandle(Isolate * isolate,double scalar)744 Handle<Object> Float64ArrayTraits::ToHandle(Isolate* isolate, double scalar) {
745   return isolate->factory()->NewNumber(scalar);
746 }
747 
ToHandle(Isolate * isolate,int64_t scalar)748 Handle<Object> BigInt64ArrayTraits::ToHandle(Isolate* isolate, int64_t scalar) {
749   return BigInt::FromInt64(isolate, scalar);
750 }
751 
ToHandle(Isolate * isolate,uint64_t scalar)752 Handle<Object> BigUint64ArrayTraits::ToHandle(Isolate* isolate,
753                                               uint64_t scalar) {
754   return BigInt::FromUint64(isolate, scalar);
755 }
756 
757 // static
758 template <class Traits>
759 STATIC_CONST_MEMBER_DEFINITION const InstanceType
760     FixedTypedArray<Traits>::kInstanceType;
761 
762 template <class Traits>
cast(Object * object)763 FixedTypedArray<Traits>* FixedTypedArray<Traits>::cast(Object* object) {
764   SLOW_DCHECK(object->IsHeapObject() &&
765               HeapObject::cast(object)->map()->instance_type() ==
766                   Traits::kInstanceType);
767   return reinterpret_cast<FixedTypedArray<Traits>*>(object);
768 }
769 
770 template <class Traits>
cast(const Object * object)771 const FixedTypedArray<Traits>* FixedTypedArray<Traits>::cast(
772     const Object* object) {
773   SLOW_DCHECK(object->IsHeapObject() &&
774               HeapObject::cast(object)->map()->instance_type() ==
775                   Traits::kInstanceType);
776   return reinterpret_cast<FixedTypedArray<Traits>*>(object);
777 }
778 
length()779 int TemplateList::length() const {
780   return Smi::ToInt(FixedArray::cast(this)->get(kLengthIndex));
781 }
782 
get(int index)783 Object* TemplateList::get(int index) const {
784   return FixedArray::cast(this)->get(kFirstElementIndex + index);
785 }
786 
set(int index,Object * value)787 void TemplateList::set(int index, Object* value) {
788   FixedArray::cast(this)->set(kFirstElementIndex + index, value);
789 }
790 
791 }  // namespace internal
792 }  // namespace v8
793 
794 #include "src/objects/object-macros-undef.h"
795 
796 #endif  // V8_OBJECTS_FIXED_ARRAY_INL_H_
797