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