| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_OBJECTS_FIXED_ARRAY_INL_H_ |
| #define V8_OBJECTS_FIXED_ARRAY_INL_H_ |
| |
| #include "src/objects/fixed-array.h" |
| |
| #include "src/handles/handles-inl.h" |
| #include "src/heap/heap-write-barrier-inl.h" |
| #include "src/numbers/conversions.h" |
| #include "src/objects/bigint.h" |
| #include "src/objects/compressed-slots.h" |
| #include "src/objects/heap-number-inl.h" |
| #include "src/objects/map.h" |
| #include "src/objects/maybe-object-inl.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/objects/oddball.h" |
| #include "src/objects/slots.h" |
| #include "src/roots/roots-inl.h" |
| #include "src/sanitizer/tsan.h" |
| |
| // Has to be the last include (doesn't have include guards): |
| #include "src/objects/object-macros.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #include "torque-generated/src/objects/fixed-array-tq-inl.inc" |
| |
| TQ_OBJECT_CONSTRUCTORS_IMPL(FixedArrayBase) |
| FixedArrayBase::FixedArrayBase(Address ptr, |
| HeapObject::AllowInlineSmiStorage allow_smi) |
| : TorqueGeneratedFixedArrayBase(ptr, allow_smi) {} |
| TQ_OBJECT_CONSTRUCTORS_IMPL(FixedArray) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(FixedDoubleArray) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(ArrayList) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(ByteArray) |
| ByteArray::ByteArray(Address ptr, HeapObject::AllowInlineSmiStorage allow_smi) |
| : TorqueGeneratedByteArray(ptr, allow_smi) {} |
| TQ_OBJECT_CONSTRUCTORS_IMPL(TemplateList) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WeakFixedArray) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WeakArrayList) |
| |
| NEVER_READ_ONLY_SPACE_IMPL(WeakArrayList) |
| |
| SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) |
| |
| SYNCHRONIZED_SMI_ACCESSORS(WeakFixedArray, length, kLengthOffset) |
| |
| SYNCHRONIZED_SMI_ACCESSORS(WeakArrayList, capacity, kCapacityOffset) |
| |
| Object FixedArrayBase::unchecked_synchronized_length() const { |
| return ACQUIRE_READ_FIELD(*this, kLengthOffset); |
| } |
| |
| ObjectSlot FixedArray::GetFirstElementAddress() { |
| return RawField(OffsetOfElementAt(0)); |
| } |
| |
| bool FixedArray::ContainsOnlySmisOrHoles() { |
| Object the_hole = GetReadOnlyRoots().the_hole_value(); |
| ObjectSlot current = GetFirstElementAddress(); |
| for (int i = 0; i < length(); ++i, ++current) { |
| Object candidate = *current; |
| if (!candidate.IsSmi() && candidate != the_hole) return false; |
| } |
| return true; |
| } |
| |
| Object FixedArray::get(int index) const { |
| IsolateRoot isolate = GetIsolateForPtrCompr(*this); |
| return get(isolate, index); |
| } |
| |
| Object FixedArray::get(IsolateRoot isolate, int index) const { |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| return TaggedField<Object>::Relaxed_Load(isolate, *this, |
| OffsetOfElementAt(index)); |
| } |
| |
| Handle<Object> FixedArray::get(FixedArray array, int index, Isolate* isolate) { |
| return handle(array.get(isolate, index), isolate); |
| } |
| |
| bool FixedArray::is_the_hole(Isolate* isolate, int index) { |
| return get(isolate, index).IsTheHole(isolate); |
| } |
| |
| void FixedArray::set(int index, Smi value) { |
| DCHECK_NE(map(), GetReadOnlyRoots().fixed_cow_array_map()); |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| DCHECK(Object(value).IsSmi()); |
| int offset = OffsetOfElementAt(index); |
| RELAXED_WRITE_FIELD(*this, offset, value); |
| } |
| |
| void FixedArray::set(int index, Object value) { |
| DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map()); |
| DCHECK(IsFixedArray()); |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| int offset = OffsetOfElementAt(index); |
| RELAXED_WRITE_FIELD(*this, offset, value); |
| WRITE_BARRIER(*this, offset, value); |
| } |
| |
| void FixedArray::set(int index, Object value, WriteBarrierMode mode) { |
| DCHECK_NE(map(), GetReadOnlyRoots().fixed_cow_array_map()); |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| int offset = OffsetOfElementAt(index); |
| RELAXED_WRITE_FIELD(*this, offset, value); |
| CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); |
| } |
| |
| // static |
| void FixedArray::NoWriteBarrierSet(FixedArray array, int index, Object value) { |
| DCHECK_NE(array.map(), array.GetReadOnlyRoots().fixed_cow_array_map()); |
| DCHECK_LT(static_cast<unsigned>(index), |
| static_cast<unsigned>(array.length())); |
| DCHECK(!ObjectInYoungGeneration(value)); |
| int offset = OffsetOfElementAt(index); |
| RELAXED_WRITE_FIELD(array, offset, value); |
| } |
| |
| Object FixedArray::synchronized_get(int index) const { |
| IsolateRoot isolate = GetIsolateForPtrCompr(*this); |
| return synchronized_get(isolate, index); |
| } |
| |
| Object FixedArray::synchronized_get(IsolateRoot isolate, int index) const { |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| return ACQUIRE_READ_FIELD(*this, OffsetOfElementAt(index)); |
| } |
| |
| void FixedArray::synchronized_set(int index, Smi value) { |
| DCHECK_NE(map(), GetReadOnlyRoots().fixed_cow_array_map()); |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| DCHECK(Object(value).IsSmi()); |
| RELEASE_WRITE_FIELD(*this, OffsetOfElementAt(index), value); |
| } |
| |
| void FixedArray::set_undefined(int index) { |
| set_undefined(GetReadOnlyRoots(), index); |
| } |
| |
| void FixedArray::set_undefined(Isolate* isolate, int index) { |
| set_undefined(ReadOnlyRoots(isolate), index); |
| } |
| |
| void FixedArray::set_undefined(ReadOnlyRoots ro_roots, int index) { |
| FixedArray::NoWriteBarrierSet(*this, index, ro_roots.undefined_value()); |
| } |
| |
| void FixedArray::set_null(int index) { set_null(GetReadOnlyRoots(), index); } |
| |
| void FixedArray::set_null(Isolate* isolate, int index) { |
| set_null(ReadOnlyRoots(isolate), index); |
| } |
| |
| void FixedArray::set_null(ReadOnlyRoots ro_roots, int index) { |
| FixedArray::NoWriteBarrierSet(*this, index, ro_roots.null_value()); |
| } |
| |
| void FixedArray::set_the_hole(int index) { |
| set_the_hole(GetReadOnlyRoots(), index); |
| } |
| |
| void FixedArray::set_the_hole(Isolate* isolate, int index) { |
| set_the_hole(ReadOnlyRoots(isolate), index); |
| } |
| |
| void FixedArray::set_the_hole(ReadOnlyRoots ro_roots, int index) { |
| FixedArray::NoWriteBarrierSet(*this, index, ro_roots.the_hole_value()); |
| } |
| |
| void FixedArray::FillWithHoles(int from, int to) { |
| for (int i = from; i < to; i++) { |
| set_the_hole(i); |
| } |
| } |
| |
| ObjectSlot FixedArray::data_start() { return RawField(OffsetOfElementAt(0)); } |
| |
| ObjectSlot FixedArray::RawFieldOfElementAt(int index) { |
| return RawField(OffsetOfElementAt(index)); |
| } |
| |
| void FixedArray::MoveElements(Isolate* isolate, int dst_index, int src_index, |
| int len, WriteBarrierMode mode) { |
| if (len == 0) return; |
| DCHECK_LE(dst_index + len, length()); |
| DCHECK_LE(src_index + len, length()); |
| DisallowHeapAllocation no_gc; |
| ObjectSlot dst_slot(RawFieldOfElementAt(dst_index)); |
| ObjectSlot src_slot(RawFieldOfElementAt(src_index)); |
| isolate->heap()->MoveRange(*this, dst_slot, src_slot, len, mode); |
| } |
| |
| void FixedArray::CopyElements(Isolate* isolate, int dst_index, FixedArray src, |
| int src_index, int len, WriteBarrierMode mode) { |
| if (len == 0) return; |
| DCHECK_LE(dst_index + len, length()); |
| DCHECK_LE(src_index + len, src.length()); |
| DisallowHeapAllocation no_gc; |
| |
| ObjectSlot dst_slot(RawFieldOfElementAt(dst_index)); |
| ObjectSlot src_slot(src.RawFieldOfElementAt(src_index)); |
| isolate->heap()->CopyRange(*this, dst_slot, src_slot, len, mode); |
| } |
| |
| // Due to left- and right-trimming, concurrent visitors need to read the length |
| // with acquire semantics. |
| // TODO(ulan): Acquire should not be needed anymore. |
| inline int FixedArray::AllocatedSize() { |
| return SizeFor(synchronized_length()); |
| } |
| inline int WeakFixedArray::AllocatedSize() { |
| return SizeFor(synchronized_length()); |
| } |
| inline int WeakArrayList::AllocatedSize() { |
| return SizeFor(synchronized_capacity()); |
| } |
| |
| // Perform a binary search in a fixed array. |
| template <SearchMode search_mode, typename T> |
| int BinarySearch(T* array, Name name, int valid_entries, |
| int* out_insertion_index) { |
| DCHECK_IMPLIES(search_mode == VALID_ENTRIES, out_insertion_index == nullptr); |
| int low = 0; |
| // We have to search on all entries, even when search_mode == VALID_ENTRIES. |
| // This is because the InternalIndex might be different from the SortedIndex |
| // (i.e the first added item in {array} could be the last in the sorted |
| // index). After doing the binary search and getting the correct internal |
| // index we check to have the index lower than valid_entries, if needed. |
| int high = array->number_of_entries() - 1; |
| uint32_t hash = name.hash(); |
| int limit = high; |
| |
| DCHECK(low <= high); |
| |
| while (low != high) { |
| int mid = low + (high - low) / 2; |
| Name mid_name = array->GetSortedKey(mid); |
| uint32_t mid_hash = mid_name.hash(); |
| |
| if (mid_hash >= hash) { |
| high = mid; |
| } else { |
| low = mid + 1; |
| } |
| } |
| |
| for (; low <= limit; ++low) { |
| int sort_index = array->GetSortedKeyIndex(low); |
| Name entry = array->GetKey(InternalIndex(sort_index)); |
| uint32_t current_hash = entry.hash(); |
| if (current_hash != hash) { |
| // 'search_mode == ALL_ENTRIES' here and below is not needed since |
| // 'out_insertion_index != nullptr' implies 'search_mode == ALL_ENTRIES'. |
| // Having said that, when creating the template for <VALID_ENTRIES> these |
| // ifs can be elided by the C++ compiler if we add 'search_mode == |
| // ALL_ENTRIES'. |
| if (search_mode == ALL_ENTRIES && out_insertion_index != nullptr) { |
| *out_insertion_index = sort_index + (current_hash > hash ? 0 : 1); |
| } |
| return T::kNotFound; |
| } |
| if (entry == name) { |
| if (search_mode == ALL_ENTRIES || sort_index < valid_entries) { |
| return sort_index; |
| } |
| return T::kNotFound; |
| } |
| } |
| |
| if (search_mode == ALL_ENTRIES && out_insertion_index != nullptr) { |
| *out_insertion_index = limit + 1; |
| } |
| return T::kNotFound; |
| } |
| |
| // Perform a linear search in this fixed array. len is the number of entry |
| // indices that are valid. |
| template <SearchMode search_mode, typename T> |
| int LinearSearch(T* array, Name name, int valid_entries, |
| int* out_insertion_index) { |
| if (search_mode == ALL_ENTRIES && out_insertion_index != nullptr) { |
| uint32_t hash = name.hash(); |
| int len = array->number_of_entries(); |
| for (int number = 0; number < len; number++) { |
| int sorted_index = array->GetSortedKeyIndex(number); |
| Name entry = array->GetKey(InternalIndex(sorted_index)); |
| uint32_t current_hash = entry.hash(); |
| if (current_hash > hash) { |
| *out_insertion_index = sorted_index; |
| return T::kNotFound; |
| } |
| if (entry == name) return sorted_index; |
| } |
| *out_insertion_index = len; |
| return T::kNotFound; |
| } else { |
| DCHECK_LE(valid_entries, array->number_of_entries()); |
| DCHECK_NULL(out_insertion_index); // Not supported here. |
| for (int number = 0; number < valid_entries; number++) { |
| if (array->GetKey(InternalIndex(number)) == name) return number; |
| } |
| return T::kNotFound; |
| } |
| } |
| |
| template <SearchMode search_mode, typename T> |
| int Search(T* array, Name name, int valid_entries, int* out_insertion_index, |
| bool concurrent_search) { |
| SLOW_DCHECK_IMPLIES(!concurrent_search, array->IsSortedNoDuplicates()); |
| |
| if (valid_entries == 0) { |
| if (search_mode == ALL_ENTRIES && out_insertion_index != nullptr) { |
| *out_insertion_index = 0; |
| } |
| return T::kNotFound; |
| } |
| |
| // Do linear search for small arrays, and for searches in the background |
| // thread. |
| const int kMaxElementsForLinearSearch = 8; |
| if (valid_entries <= kMaxElementsForLinearSearch || concurrent_search) { |
| return LinearSearch<search_mode>(array, name, valid_entries, |
| out_insertion_index); |
| } |
| |
| return BinarySearch<search_mode>(array, name, valid_entries, |
| out_insertion_index); |
| } |
| |
| double FixedDoubleArray::get_scalar(int index) { |
| DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && |
| map() != GetReadOnlyRoots().fixed_array_map()); |
| DCHECK(index >= 0 && index < this->length()); |
| DCHECK(!is_the_hole(index)); |
| return ReadField<double>(kHeaderSize + index * kDoubleSize); |
| } |
| |
| uint64_t FixedDoubleArray::get_representation(int index) { |
| DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && |
| map() != GetReadOnlyRoots().fixed_array_map()); |
| DCHECK(index >= 0 && index < this->length()); |
| int offset = kHeaderSize + index * kDoubleSize; |
| // Bug(v8:8875): Doubles may be unaligned. |
| return base::ReadUnalignedValue<uint64_t>(field_address(offset)); |
| } |
| |
| Handle<Object> FixedDoubleArray::get(FixedDoubleArray array, int index, |
| Isolate* isolate) { |
| if (array.is_the_hole(index)) { |
| return ReadOnlyRoots(isolate).the_hole_value_handle(); |
| } else { |
| return isolate->factory()->NewNumber(array.get_scalar(index)); |
| } |
| } |
| |
| void FixedDoubleArray::set(int index, double value) { |
| DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && |
| map() != GetReadOnlyRoots().fixed_array_map()); |
| int offset = kHeaderSize + index * kDoubleSize; |
| if (std::isnan(value)) { |
| WriteField<double>(offset, std::numeric_limits<double>::quiet_NaN()); |
| } else { |
| WriteField<double>(offset, value); |
| } |
| DCHECK(!is_the_hole(index)); |
| } |
| |
| void FixedDoubleArray::set_the_hole(Isolate* isolate, int index) { |
| set_the_hole(index); |
| } |
| |
| void FixedDoubleArray::set_the_hole(int index) { |
| DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && |
| map() != GetReadOnlyRoots().fixed_array_map()); |
| int offset = kHeaderSize + index * kDoubleSize; |
| base::WriteUnalignedValue<uint64_t>(field_address(offset), kHoleNanInt64); |
| } |
| |
| bool FixedDoubleArray::is_the_hole(Isolate* isolate, int index) { |
| return is_the_hole(index); |
| } |
| |
| bool FixedDoubleArray::is_the_hole(int index) { |
| return get_representation(index) == kHoleNanInt64; |
| } |
| |
| void FixedDoubleArray::MoveElements(Isolate* isolate, int dst_index, |
| int src_index, int len, |
| WriteBarrierMode mode) { |
| DCHECK_EQ(SKIP_WRITE_BARRIER, mode); |
| double* data_start = reinterpret_cast<double*>(field_address(kHeaderSize)); |
| MemMove(data_start + dst_index, data_start + src_index, len * kDoubleSize); |
| } |
| |
| void FixedDoubleArray::FillWithHoles(int from, int to) { |
| for (int i = from; i < to; i++) { |
| set_the_hole(i); |
| } |
| } |
| |
| MaybeObject WeakFixedArray::Get(int index) const { |
| IsolateRoot isolate = GetIsolateForPtrCompr(*this); |
| return Get(isolate, index); |
| } |
| |
| MaybeObject WeakFixedArray::Get(IsolateRoot isolate, int index) const { |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); |
| return objects(isolate, index); |
| } |
| |
| void WeakFixedArray::Set(int index, MaybeObject value, WriteBarrierMode mode) { |
| set_objects(index, value, mode); |
| } |
| |
| MaybeObjectSlot WeakFixedArray::data_start() { |
| return RawMaybeWeakField(kObjectsOffset); |
| } |
| |
| MaybeObjectSlot WeakFixedArray::RawFieldOfElementAt(int index) { |
| return RawMaybeWeakField(OffsetOfElementAt(index)); |
| } |
| |
| void WeakFixedArray::CopyElements(Isolate* isolate, int dst_index, |
| WeakFixedArray src, int src_index, int len, |
| WriteBarrierMode mode) { |
| if (len == 0) return; |
| DCHECK_LE(dst_index + len, length()); |
| DCHECK_LE(src_index + len, src.length()); |
| DisallowHeapAllocation no_gc; |
| |
| MaybeObjectSlot dst_slot(data_start() + dst_index); |
| MaybeObjectSlot src_slot(src.data_start() + src_index); |
| isolate->heap()->CopyRange(*this, dst_slot, src_slot, len, mode); |
| } |
| |
| MaybeObject WeakArrayList::Get(int index) const { |
| IsolateRoot isolate = GetIsolateForPtrCompr(*this); |
| return Get(isolate, index); |
| } |
| |
| MaybeObject WeakArrayList::Get(IsolateRoot isolate, int index) const { |
| DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(capacity())); |
| return objects(isolate, index); |
| } |
| |
| void WeakArrayList::Set(int index, MaybeObject value, WriteBarrierMode mode) { |
| set_objects(index, value, mode); |
| } |
| |
| MaybeObjectSlot WeakArrayList::data_start() { |
| return RawMaybeWeakField(kObjectsOffset); |
| } |
| |
| void WeakArrayList::CopyElements(Isolate* isolate, int dst_index, |
| WeakArrayList src, int src_index, int len, |
| WriteBarrierMode mode) { |
| if (len == 0) return; |
| DCHECK_LE(dst_index + len, capacity()); |
| DCHECK_LE(src_index + len, src.capacity()); |
| DisallowHeapAllocation no_gc; |
| |
| MaybeObjectSlot dst_slot(data_start() + dst_index); |
| MaybeObjectSlot src_slot(src.data_start() + src_index); |
| isolate->heap()->CopyRange(*this, dst_slot, src_slot, len, mode); |
| } |
| |
| HeapObject WeakArrayList::Iterator::Next() { |
| if (!array_.is_null()) { |
| while (index_ < array_.length()) { |
| MaybeObject item = array_.Get(index_++); |
| DCHECK(item->IsWeakOrCleared()); |
| if (!item->IsCleared()) return item->GetHeapObjectAssumeWeak(); |
| } |
| array_ = WeakArrayList(); |
| } |
| return HeapObject(); |
| } |
| |
| int ArrayList::Length() const { |
| if (FixedArray::cast(*this).length() == 0) return 0; |
| return Smi::ToInt(FixedArray::cast(*this).get(kLengthIndex)); |
| } |
| |
| void ArrayList::SetLength(int length) { |
| return FixedArray::cast(*this).set(kLengthIndex, Smi::FromInt(length)); |
| } |
| |
| Object ArrayList::Get(int index) const { |
| return FixedArray::cast(*this).get(kFirstIndex + index); |
| } |
| |
| Object ArrayList::Get(IsolateRoot isolate, int index) const { |
| return FixedArray::cast(*this).get(isolate, kFirstIndex + index); |
| } |
| |
| ObjectSlot ArrayList::Slot(int index) { |
| return RawField(OffsetOfElementAt(kFirstIndex + index)); |
| } |
| |
| void ArrayList::Set(int index, Object obj, WriteBarrierMode mode) { |
| FixedArray::cast(*this).set(kFirstIndex + index, obj, mode); |
| } |
| |
| void ArrayList::Clear(int index, Object undefined) { |
| DCHECK(undefined.IsUndefined()); |
| FixedArray::cast(*this).set(kFirstIndex + index, undefined, |
| SKIP_WRITE_BARRIER); |
| } |
| |
| int ByteArray::Size() { return RoundUp(length() + kHeaderSize, kTaggedSize); } |
| |
| byte ByteArray::get(int index) const { |
| DCHECK(index >= 0 && index < this->length()); |
| return ReadField<byte>(kHeaderSize + index * kCharSize); |
| } |
| |
| void ByteArray::set(int index, byte value) { |
| DCHECK(index >= 0 && index < this->length()); |
| WriteField<byte>(kHeaderSize + index * kCharSize, value); |
| } |
| |
| void ByteArray::copy_in(int index, const byte* buffer, int length) { |
| DCHECK(index >= 0 && length >= 0 && length <= kMaxInt - index && |
| index + length <= this->length()); |
| Address dst_addr = field_address(kHeaderSize + index * kCharSize); |
| memcpy(reinterpret_cast<void*>(dst_addr), buffer, length); |
| } |
| |
| void ByteArray::copy_out(int index, byte* buffer, int length) { |
| DCHECK(index >= 0 && length >= 0 && length <= kMaxInt - index && |
| index + length <= this->length()); |
| Address src_addr = field_address(kHeaderSize + index * kCharSize); |
| memcpy(buffer, reinterpret_cast<void*>(src_addr), length); |
| } |
| |
| int ByteArray::get_int(int index) const { |
| DCHECK(index >= 0 && index < this->length() / kIntSize); |
| return ReadField<int>(kHeaderSize + index * kIntSize); |
| } |
| |
| void ByteArray::set_int(int index, int value) { |
| DCHECK(index >= 0 && index < this->length() / kIntSize); |
| WriteField<int>(kHeaderSize + index * kIntSize, value); |
| } |
| |
| uint32_t ByteArray::get_uint32(int index) const { |
| DCHECK(index >= 0 && index < this->length() / kUInt32Size); |
| return ReadField<uint32_t>(kHeaderSize + index * kUInt32Size); |
| } |
| |
| void ByteArray::set_uint32(int index, uint32_t value) { |
| DCHECK(index >= 0 && index < this->length() / kUInt32Size); |
| WriteField<uint32_t>(kHeaderSize + index * kUInt32Size, value); |
| } |
| |
| uint32_t ByteArray::get_uint32_relaxed(int index) const { |
| DCHECK(index >= 0 && index < this->length() / kUInt32Size); |
| return RELAXED_READ_UINT32_FIELD(*this, kHeaderSize + index * kUInt32Size); |
| } |
| |
| void ByteArray::set_uint32_relaxed(int index, uint32_t value) { |
| DCHECK(index >= 0 && index < this->length() / kUInt32Size); |
| RELAXED_WRITE_UINT32_FIELD(*this, kHeaderSize + index * kUInt32Size, value); |
| } |
| |
| void ByteArray::clear_padding() { |
| int data_size = length() + kHeaderSize; |
| memset(reinterpret_cast<void*>(address() + data_size), 0, Size() - data_size); |
| } |
| |
| ByteArray ByteArray::FromDataStartAddress(Address address) { |
| DCHECK_TAG_ALIGNED(address); |
| return ByteArray::cast(Object(address - kHeaderSize + kHeapObjectTag)); |
| } |
| |
| int ByteArray::DataSize() const { return RoundUp(length(), kTaggedSize); } |
| |
| int ByteArray::ByteArraySize() { return SizeFor(this->length()); } |
| |
| byte* ByteArray::GetDataStartAddress() { |
| return reinterpret_cast<byte*>(address() + kHeaderSize); |
| } |
| |
| byte* ByteArray::GetDataEndAddress() { |
| return GetDataStartAddress() + length(); |
| } |
| |
| template <class T> |
| PodArray<T>::PodArray(Address ptr) : ByteArray(ptr) {} |
| |
| template <class T> |
| PodArray<T> PodArray<T>::cast(Object object) { |
| return PodArray<T>(object.ptr()); |
| } |
| |
| // static |
| template <class T> |
| Handle<PodArray<T>> PodArray<T>::New(Isolate* isolate, int length, |
| AllocationType allocation) { |
| return Handle<PodArray<T>>::cast( |
| isolate->factory()->NewByteArray(length * sizeof(T), allocation)); |
| } |
| |
| template <class T> |
| int PodArray<T>::length() const { |
| return ByteArray::length() / sizeof(T); |
| } |
| |
| int TemplateList::length() const { |
| return Smi::ToInt(FixedArray::cast(*this).get(kLengthIndex)); |
| } |
| |
| Object TemplateList::get(int index) const { |
| return FixedArray::cast(*this).get(kFirstElementIndex + index); |
| } |
| |
| Object TemplateList::get(IsolateRoot isolate, int index) const { |
| return FixedArray::cast(*this).get(isolate, kFirstElementIndex + index); |
| } |
| |
| void TemplateList::set(int index, Object value) { |
| FixedArray::cast(*this).set(kFirstElementIndex + index, value); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| #endif // V8_OBJECTS_FIXED_ARRAY_INL_H_ |