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