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